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

Sok*_*oko 7 closures type-alias swift

我正在尝试创建一些闭包定义,我将在我的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})
Run Code Online (Sandbox Code Playgroud)

我错过了什么或者它在Swift中不受支持吗?谢谢

编辑/添加:

以上只是一个简单的例子.在现实生活中,我的类型更复杂.就像是:

typealias RealLifeClosure = (number: Int, factor: NSDecimalNumber!, key: String, upperCase: Bool) -> NSAttributedString
Run Code Online (Sandbox Code Playgroud)

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

Nat*_*ook 9

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

AnonymousFunction({(another: Int) -> Bool in return another < 0})
Run Code Online (Sandbox Code Playgroud)

令人高兴的是,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 }
Run Code Online (Sandbox Code Playgroud)

  • 把你的类型别名想象成*类型* - 它不能成为作用于该闭包的实际参数,它只定义它们是什么.这是`let`:Int = 3`中`number`和`Int`之间的区别. (2认同)
  • 我得到了你想要做的事情,但我认为你要获得的最好的是避免给出参数的类型 - 你无法避免命名它们.但是因为类型更像是一种痛苦/混乱(我认为输入`{number,factor,key in ...}'可能比依赖其他地方定义的名称更合理)它并不是那么糟糕. (2认同)

Air*_*ity 7

我认为你不能做你想做的事.为了略微简化您的示例,您可以这样做:

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

NamedFunction( { $0 < 5 } as NamedCheck)
Run Code Online (Sandbox Code Playgroud)

但是你不能做你想要的,这是依赖于一个事实,即number在闭包内部调用元组arg 而不将它作为闭包的一部分给出:

// compiler error, no idea what "number" is
let g: NamedCheck = { number < 5 }
Run Code Online (Sandbox Code Playgroud)

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

let g: NamedCheck = { number in number < 5 }
Run Code Online (Sandbox Code Playgroud)

而且,你可以随意命名它:

let h: NamedCheck = { whatevs in whatevs < 5 }
NamedFunction(h)
Run Code Online (Sandbox Code Playgroud)

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

func takesNamedArgument(#namedArg: Int) { etc... }
Run Code Online (Sandbox Code Playgroud)

或者,写下它:

func takesNamedArgument(namedArg namedArg: Int) { etc... }
Run Code Online (Sandbox Code Playgroud)

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

func takesNamedArgument(namedArg whatevs: Int) { etc... }
Run Code Online (Sandbox Code Playgroud)

我认为这是与命名元组的闭包发生的事情."外部"名称是"数字",但您必须给它一个"内部"名称,这是您必须在函数体中使用的名称.您无法在函数中使用外部参数.在闭包表达式的情况下,如果你没有给出内部名称,你可以使用$0etc,但你不能只是跳过它,除了你可以完全跳过内部名称并且在定义时只依赖外部名称常规功能.

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

let f = { (#a: Int, #b: Int)->Bool in a < b }
Run Code Online (Sandbox Code Playgroud)

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

let g = { (number1 a: Int, number2 b: Int)->Bool in a < b }
Run Code Online (Sandbox Code Playgroud)

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