I saw some code on another question that seems to create an anonymous function (closure expression) with some unusual syntax:
let plus: (Int, Int) -> Int = (+)
I understand the left side—that it's declaring a constant of type (Int, Int) -> Int
(a function that takes two Integers and returns an Integer). But what is (+)
? How can it declare a function without curly brackets, and how does it refer to the two arguments when there are no argument labels of any kind?
The function takes two arguments, adds them together, and returns the result. If I replace the +
operator with a different one (say a *
), the operation changes. So is it some kind of shorthand for {$0 + $1}
? If so, what is the logic behind this shorthand?
Actually, this is no shorthand.
plus
is a variable of type (Int, Int) -> Int
. You can assign it any object that is of this type (or any of its subtypes). A literal lambda closure is certainly of this type, but actually a named function or method would also do. And that is exactly what is happening here.
It is assigning the operator method object named +
to the variable.
This is mentioned sort-of implicitly in the Closures chapter of the language guide:
Operator Methods
There’s actually an even shorter way to write the closure expression above. Swift’s
String
type defines its string-specific implementation of the greater-than operator (>
) as a method that has two parameters of typeString
, and returns a value of typeBool
. This exactly matches the method type needed by thesorted(by:)
method. Therefore, you can simply pass in the greater-than operator, and Swift will infer that you want to use its string-specific implementation:reversedNames = names.sorted(by: >)
So, what the code is doing is assigning the Operator Method +
to the variable plus
. +
is simply the name of the function assigned to the variable. No magic shorthand involved.
Would you be surprised to see this?
let plus: (Int, Int) -> Int = foo
+
is an infix
operator and a function name in Swift. There are many such functions defined on many types (it is overloaded).
You can define +
for your own custom type. For example:
struct Foo {
var value: Int
static func +(_ lhs: Foo, _ rhs: Foo) -> Foo {
return Foo(value: lhs.value + rhs.value)
}
}
var f1 = Foo(value: 5)
var f2 = Foo(value: 3)
let f3 = f1 + f2
print(f3.value) // 8
This works:
let plus: (Int, Int) -> Int = (+)
because the signature of the +
function has been fully specified, so Swift is able to identify the correct +
function.
And if we want to assign our new +
function to plus
:
let plus: (Foo, Foo) -> Foo = (+)
It's really no different than this:
func add(_ a: Int, _ b: Double) -> Double {
return Double(a) + b
}
let plus: (Int, Double) -> Double = add
print(plus(3, 4.2)) // 7.2
So why the parentheses? Why specify
(+)
instead of just+
?
+
is also a unary operator in Swift.
For example, you can say:
let x = +5
So just trying to say:
let plus: (Int, Int) -> Int = +
confuses the compiler because it is treating the +
as a unary prefix operator and it is expecting the +
to be followed by something else such as 5
. By surrounding it with parentheses, the Swift compiler then stops trying to parse +
as a unary operator and treats is just as its function name. Even if +
weren't a unary prefix operator, Swift would still be expecting values on either side of the +
, so the parentheses tell Swift that you aren't providing any inputs to the function, but just want the function itself.
You can refer to the +
function without the parentheses in situations where it isn't ambiguous. For example:
var arr = [1, 2, 3]
let sum = arr.reduce(0, +)
(+)
by itself is an operator method. You can declare your own operator like this:
precedencegroup CompositionPrecedence {
associativity: left
higherThan: AssignmentPrecedence
}
infix operator •: CompositionPrecedence
func •(a: Int, b: Int) -> Int {
return a + b
}
Usage will be the same:
var closure: (Int, Int) -> Int = (•)
print("\(closure(1, 2))")
来源:https://stackoverflow.com/questions/52093049/anonymous-function-with-no-curly-braces-and-no-argument-labels