简体   繁体   English

Swift:重用闭包定义(带有typealias)

[英]Swift: reusing a closure definition (with typealias)

I'm trying to do create some closure definitions which I'm gonna use a lot in my iOS app. 我正在尝试创建一些关闭定义,这些定义将在我的iOS应用程序中使用很多。 So I thought to use a typealias as it seemed the most promising ... 所以我认为使用typealias似乎是最有前途的...

I did a small Playground example which shows my issue in detail 我做了一个小的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})

Am I missing something or is it just not supported in Swift? 我是否缺少某些东西?Swift是否不支持它? Thanks 谢谢

EDIT/ADDITION: 编辑/添加:

The above is just a simple example. 以上只是一个简单的例子。 In real life my typealias is more complicated. 在现实生活中,我的打字错误更为复杂。 Something like: 就像是:

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

I basically want to use a typealias as a shortcut so I don't have to type that much. 我基本上想使用typealias作为快捷方式,所以我不必输入太多。 Maybe typealias isn't the right choice... Is there another? 也许typealias不是正确的选择...还有另一个吗?

You aren't rewriting the typealias declaration in this code, you're declaring the parameters and return type: 您不是在此代码中重写typealias声明,而是在声明参数和返回类型:

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

Happily, Swift's type inference lets you use any of the following - pick the style that feels best to you: 幸运的是,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 }

I don't think you'll be able to do what you want. 我认为您无法做自己想做的事。 To simplify your example slightly, you can do this: 为了稍微简化示例,您可以执行以下操作:

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

NamedFunction( { $0 < 5 } as NamedCheck)

But you can't do what you want, which is to rely on the fact that the tuple arg is called number to refer to it inside the closure without giving it as part of the closure: 但是您不能做您想做的事,这是依赖于元组arg被称为number的事实,它在闭包内部引用了它而没有将其作为闭包的一部分:

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

Bear in mind that you can name the parameter without giving it a type (which is inferred from the type of g ): 请记住,您可以在不给参数指定类型的情况下命名该参数(由g的类型推断):

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

but also, you can name it whatever you want: 而且,您也可以根据需要命名:

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

Here's what I think is happening (this is partly guesswork). 我认为这是正在发生的事情(部分是猜测)。 Remember how functions can have external and internal argument names: 记住函数如何具有外部和内部参数名称:

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

Or, to write it longhand: 或者,长期写:

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

But you can also give as the second, internal, name whatever you like: 但您也可以随便给第二个内部名称命名:

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

I think this is what is happening with the closures with named tuples. 我认为这就是命名元组的闭包正在发生的事情。 The "external" name is "number", but you must give it an "internal" name too, which is what you must use in the function body. “外部”名称是“数字”,但是您也必须给它一个“内部”名称,这是您必须在函数主体中使用的名称。 You can't make use of the external argument within your function. 您不能在函数内使用外部参数。 In case of closure expressions, if you don't give an internal name, you can use $0 etc, but you can't just skip it, any more than you can skip the internal name altogether and just rely on the external name when defining a regular function. 在闭包表达式的情况下,如果不提供内部名称,则可以使用$0等,但不能仅跳过它,而不能完全跳过内部名称,并且在定义时仅依赖外部名称常规功能。

I was hoping that I could prove this theory by the following: 我希望可以通过以下方式证明这一理论:

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

resulting in f being of type (a: Int, b: Int)->Bool) . 导致f为类型(a: Int, b: Int)->Bool) This compiles, as does: 编译如下:

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

but it doesn't look like the external names for the argument make it out to the type of f or g . 但是看起来参数的外部名称看起来不像fg的类型。

The syntax to create a closure is: 创建闭包的语法为:

{ (parameters) -> return type in
    statements
}

What's at the left of in is the closure signature (parameters and return value). in左边是闭包签名(参数和返回值)。 In some cases the signature can be omitted or simplified when type inference is able to determine the number of parameters and their type, and the return value. 在某些情况下,当类型推断能够确定参数的数量及其类型以及返回值时,可以省略或简化签名。

In your case it doesn't work because you are passing a type alias, but it is interpreted as a parameter name. 在您的情况下,它不起作用,因为您要传递类型别名,但是它将被解释为参数名称。 The 3 lines work if either you: 如果您符合以下三个条件,则这三行有效:

  1. name the parameter properly 正确命名参数

     NamedFunction({number in return number < 0}) AnonymousFunction({number in return number < 0}) 
  2. use shorthand arguments: 使用速记参数:

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM