Swift:重用闭包定义(带类型)

时间:2015-01-06 17:30:30

标签: swift closures type-alias

我正在尝试创建一些我将在我的iOS应用程序中使用很多的闭包定义。所以我想使用一个类型,因为它看起来最有希望......

我做了一个小型的Playground示例,详细显示了我的问题

// Here are two tries for the Closure I need
typealias AnonymousCheck = (Int) -> Bool
typealias NamedCheck = (number: Int) -> Bool

// This works fine
var var1: AnonymousCheck = {
    return $0 > 0
}
var1(-2)
var1(3343)

// This works fine
var var2: NamedCheck = {
    return $0 > 0
}
var2(number: -2)
var2(number: 12)

// But I want to use the typealias mainly as function parameter!
// So:

// Use typealias as function parameter
func NamedFunction(closure: NamedCheck) {
    closure(number: 3)
}
func AnonymousFunction(closure: AnonymousCheck) {
    closure(3)
}

// This works as well
// But why write again the typealias declaration?
AnonymousFunction({(another: Int) -> Bool in return another < 0})
NamedFunction({(another: Int) -> Bool in return another < 0})

// This is what I want... which doesn't work
// ERROR: Use of unresolved identifier 'number'
NamedFunction({NamedCheck in return number < 0})

// Not even these work
// ERROR for both: Anonymous closure arguments cannot be used inside a closure that has exlicit arguments
NamedFunction({NamedCheck in return $0 < 0})
AnonymousFunction({AnonymousCheck in return $0 < 0})

我是否遗漏了某些东西,或者它是否在Swift中不受支持? 感谢

EDIT / ADDITION:

以上只是一个简单的例子。在现实生活中,我的类型更复杂。类似的东西:

typealias RealLifeClosure = (number: Int, factor: NSDecimalNumber!, key: String, upperCase: Bool) -> NSAttributedString

我基本上想要使用一个typealias作为快捷方式,所以我不必输入那么多。也许typealias不是正确的选择......还有另一个吗?

3 个答案:

答案 0 :(得分:9)

您没有在此代码中重写typealias声明,而是声明参数和返回类型:

AnonymousFunction({(another: Int) -> Bool in return another < 0})

令人高兴的是,Swift的类型推断让您可以使用以下任何一种方式 - 选择最适合您的风格:

AnonymousFunction( { (number: Int) -> Bool in number < 0 } )
AnonymousFunction { (number: Int) -> Bool in number < 0 }
AnonymousFunction { (number) -> Bool in number < 0 }
AnonymousFunction { number -> Bool in number < 0 }
AnonymousFunction { number in number < 0 }
AnonymousFunction { $0 < 0 }

答案 1 :(得分:7)

我不认为你能做你想做的事。为了略微简化您的示例,您可以执行以下操作:

typealias NamedCheck = (number: Int) -> Bool
let f: NamedCheck = { $0 < 5 }
f(number: 1)
NamedFunction(f)

NamedFunction( { $0 < 5 } as NamedCheck)

但是你不能做你想做的事情,这就是依赖于元组arg被称为number以在闭包内引用它而不将其作为闭包的一部分的事实: / p>

// compiler error, no idea what "number" is
let g: NamedCheck = { number < 5 }

请记住,您可以为参数命名而不为其指定类型(从g的类型推断出来):

let g: NamedCheck = { number in number < 5 }

但是,您可以随意命名:

let h: NamedCheck = { whatevs in whatevs < 5 }
NamedFunction(h)

这就是我认为正在发生的事情(这是部分猜测)。记住函数如何具有外部和内部参数名称:

func takesNamedArgument(#namedArg: Int) { etc... }

或者,写得很简单:

func takesNamedArgument(namedArg namedArg: Int) { etc... }

但你也可以作为第二个内部名称给予你喜欢的名字:

func takesNamedArgument(namedArg whatevs: Int) { etc... }

我认为这就是使用命名元组的闭包所发生的事情。 &#34;外部&#34; name是&#34; number&#34;,但你必须给它一个&#34;内部&#34;也是名称,这是你必须在函数体中使用的。您无法在函数中使用外部参数。如果是关闭表达式,如果您没有提供内部名称,则可以使用$0等,但您不能跳过它,只要您可以完全跳过内部名称,在定义常规函数时只需依赖外部名称。

我希望我能通过以下方式证明这一理论:

let f = { (#a: Int, #b: Int)->Bool in a < b }

导致f属于(a: Int, b: Int)->Bool)类型。这样编译,如下:

let g = { (number1 a: Int, number2 b: Int)->Bool in a < b }

但它看起来不像参数的外部名称使其成为fg的类型。

答案 2 :(得分:3)

创建闭包的语法是:

{ (parameters) -> return type in
    statements
}

in左侧的内容是闭包签名(参数和返回值)。在某些情况下,当类型推断能够确定参数的数量及其类型和返回值时,可以省略或简化签名。

在您的情况下,它不起作用,因为您传递的是类型别名,但它被解释为参数名称。如果您:

,则3行有效
  1. 正确命名参数

    NamedFunction({number in return number < 0})
    AnonymousFunction({number in  return number < 0})
    
  2. 使用简写参数:

    NamedFunction({ return $0 < 0})
    AnonymousFunction({ return $0 < 0})
    
  3. 使用简写参数和隐式返回:

    NamedFunction({ $0 < 0})
    AnonymousFunction({ $0 < 0})