Swift: reusing a closure definition (using types)

I am trying to create some closure definitions that I am going to use in my iOS application. Therefore, I thought to use typals, because it seemed the most promising ...

I made a small example of a playground that details my problem.

// 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? Thanks

EDIT / Add:

The above example is a simple example. In real life, my types were harder. Sort of:

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

Basically I want to use typealias as a shortcut, so I don't need to type so much. Maybe typealias is not the right choice ... Is there another?

+6
source share
3 answers

You do not rewrite the typealias in this code, you declare the parameters and return the type:

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

Fortunately, Swift type inference allows you to use any of the following: choose the style that suits you best:

 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 } 
+9
source

I don’t think you can do what you want. To simplify your example a bit, 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 to rely on the arg tuple called number to refer to it inside the closure without providing it as part of the closure:

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

Keep in mind that you can name a parameter without specifying its type (which is inferred from type g ):

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

but also you can name it as you want:

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

Here I think this is happening (this is partly a guess). Remember how functions can have names of external and internal arguments:

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

Or to write this longhand:

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

But you can also specify as the second, internal, name that you like:

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

I think this is what happens with the closure with the named tuples. The "external" name is "number", but you must also give it the "internal" name, which you must use in the body of the function. You cannot use an external argument inside your function. In the case of closure expressions, if you do not specify an internal name, you can use $0 , etc., but you can’t just skip it, nothing more, you can skip the internal name altogether and just rely on the external name when defining a regular function .

I was hoping I could prove this theory as follows:

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

as a result, f is of type (a: Int, b: Int)->Bool) . This compiles, like:

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

but it doesn’t look like the external argument names represent type f or g .

+6
source

The syntax for creating a closure is:

 { (parameters) -> return type in statements } 

Which to the left of in is the closure signature (parameters and return value). In some cases, a signature may be omitted or simplified when type inference can determine the number of parameters and their type and return value.

In your case, this does not work, because you pass a type alias, but it is interpreted as a parameter name. 3 lines work if you:

  • specify the parameter correctly

     NamedFunction({number in return number < 0}) AnonymousFunction({number in return number < 0}) 
  • use shorthand arguments:

     NamedFunction({ return $0 < 0}) AnonymousFunction({ return $0 < 0}) 
  • use shorthand arguments and implicit return:

     NamedFunction({ $0 < 0}) AnonymousFunction({ $0 < 0}) 
+2
source

Source: https://habr.com/ru/post/980604/


All Articles