Swift:重用闭包定义(使用类型别名)
Swift: reusing a closure definition (with typealias)
我正在尝试创建一些我将在我的 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
}
var1(-2)
var1(3343)
// This works fine
var var2: NamedCheck = {
return [==] > 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})
AnonymousFunction({AnonymousCheck in return [==] < 0})
我是不是遗漏了什么,或者只是 Swift 不支持它?
谢谢
EDIT/ADDITION:
以上只是一个简单的例子。在现实生活中,我的 typealias 更复杂。类似于:
typealias RealLifeClosure = (number: Int, factor: NSDecimalNumber!, key: String, upperCase: Bool) -> NSAttributedString
我基本上想使用 typealias 作为快捷方式,这样我就不必输入那么多了。也许 typealias 不是正确的选择...还有另一个吗?
创建闭包的语法是:
{ (parameters) -> return type in
statements
}
in
左边是闭包签名(参数和return值)。在某些情况下,当类型推断能够确定参数的数量及其类型以及 return 值时,可以省略或简化签名。
在你的情况下它不起作用,因为你传递的是类型别名,但它被解释为参数名称。如果您满足以下条件,则 3 行有效:
正确命名参数
NamedFunction({number in return number < 0})
AnonymousFunction({number in return number < 0})
使用 shorthand 个参数:
NamedFunction({ return [=12=] < 0})
AnonymousFunction({ return [=12=] < 0})
使用 shorthand 参数和隐式 return:
NamedFunction({ [=13=] < 0})
AnonymousFunction({ [=13=] < 0})
您不是在重写此代码中的 typealias
声明,您是在声明参数和 return 类型:
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 { [=11=] < 0 }
我不认为你能做你想做的事。为了稍微简化您的示例,您可以这样做:
typealias NamedCheck = (number: Int) -> Bool
let f: NamedCheck = { [=10=] < 5 }
f(number: 1)
NamedFunction(f)
NamedFunction( { [=10=] < 5 } as NamedCheck)
但是你不能做你想做的事,这依赖于元组 arg 被称为 number
在闭包中引用它而不将其作为闭包的一部分的事实:
// 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... }
我认为这就是带有命名元组的闭包所发生的情况。 "external" 名称是 "number",但您也必须给它一个 "internal" 名称,这是您必须在函数体中使用的名称。您不能在函数中使用外部参数。在闭包表达式的情况下,如果你不给出内部名称,你可以使用 [=21=]
等,但你不能跳过它,就像你不能完全跳过内部名称而只依赖定义常规函数时的外部名称。
我希望我可以通过以下方式证明这个理论:
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 }
但是参数的外部名称看起来不像是 f
或 g
的类型。
我正在尝试创建一些我将在我的 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
}
var1(-2)
var1(3343)
// This works fine
var var2: NamedCheck = {
return [==] > 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})
AnonymousFunction({AnonymousCheck in return [==] < 0})
我是不是遗漏了什么,或者只是 Swift 不支持它? 谢谢
EDIT/ADDITION:
以上只是一个简单的例子。在现实生活中,我的 typealias 更复杂。类似于:
typealias RealLifeClosure = (number: Int, factor: NSDecimalNumber!, key: String, upperCase: Bool) -> NSAttributedString
我基本上想使用 typealias 作为快捷方式,这样我就不必输入那么多了。也许 typealias 不是正确的选择...还有另一个吗?
创建闭包的语法是:
{ (parameters) -> return type in
statements
}
in
左边是闭包签名(参数和return值)。在某些情况下,当类型推断能够确定参数的数量及其类型以及 return 值时,可以省略或简化签名。
在你的情况下它不起作用,因为你传递的是类型别名,但它被解释为参数名称。如果您满足以下条件,则 3 行有效:
正确命名参数
NamedFunction({number in return number < 0}) AnonymousFunction({number in return number < 0})
使用 shorthand 个参数:
NamedFunction({ return [=12=] < 0}) AnonymousFunction({ return [=12=] < 0})
使用 shorthand 参数和隐式 return:
NamedFunction({ [=13=] < 0}) AnonymousFunction({ [=13=] < 0})
您不是在重写此代码中的 typealias
声明,您是在声明参数和 return 类型:
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 { [=11=] < 0 }
我不认为你能做你想做的事。为了稍微简化您的示例,您可以这样做:
typealias NamedCheck = (number: Int) -> Bool
let f: NamedCheck = { [=10=] < 5 }
f(number: 1)
NamedFunction(f)
NamedFunction( { [=10=] < 5 } as NamedCheck)
但是你不能做你想做的事,这依赖于元组 arg 被称为 number
在闭包中引用它而不将其作为闭包的一部分的事实:
// 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... }
我认为这就是带有命名元组的闭包所发生的情况。 "external" 名称是 "number",但您也必须给它一个 "internal" 名称,这是您必须在函数体中使用的名称。您不能在函数中使用外部参数。在闭包表达式的情况下,如果你不给出内部名称,你可以使用 [=21=]
等,但你不能跳过它,就像你不能完全跳过内部名称而只依赖定义常规函数时的外部名称。
我希望我可以通过以下方式证明这个理论:
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 }
但是参数的外部名称看起来不像是 f
或 g
的类型。