没有花括号和参数标签的匿名函数?
Anonymous function with no curly braces and no argument labels?
我在 上看到一些代码似乎用一些不寻常的语法创建了一个匿名函数(闭包表达式):
let plus: (Int, Int) -> Int = (+)
我理解左侧 — 它声明了一个 (Int, Int) -> Int
类型的常量(一个接受两个整数和 returns 一个整数的函数)。但是 (+)
是什么?它如何声明一个没有大括号的函数,当没有任何类型的参数标签时它如何引用两个参数?
该函数接受两个参数,将它们相加,returns 结果。如果我将 +
运算符替换为不同的运算符(比如 *
),则操作会发生变化。那么它是某种 shorthand 用于 {[=15=] + }
吗?如果是这样,这shorthand背后的逻辑是什么?
其实这不是shorthand。
plus
是 (Int, Int) -> Int
类型的变量。您可以将任何属于此类型(或其任何子类型)的对象分配给它。文字 lambda 闭包当然是这种类型,但实际上命名函数或方法也可以。这正是这里正在发生的事情。
正在将名为+
的运算符方法对象赋值给变量。
这在 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 type String
, and returns a value of type Bool
. This exactly matches the method type needed by the sorted(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: >)
因此,代码所做的是将 运算符方法 +
分配给变量 plus
。 +
只是分配给变量的函数的名称。没有魔法 shorthand 涉及。
看到这个你会不会很惊讶?
let plus: (Int, Int) -> Int = foo
+
是 infix
运算符和 Swift 中的 函数名 。在许多类型上定义了许多这样的函数(它被重载了)。
您可以为自己的自定义类型定义 +
。例如:
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
这个有效:
let plus: (Int, Int) -> Int = (+)
因为+
函数的签名已经完全指定,所以Swift能够识别正确的+
函数。
如果我们想将新的 +
函数分配给 plus
:
let plus: (Foo, Foo) -> Foo = (+)
真的和这个没什么区别:
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 +
?
+
也是 Swift.
中的一元运算符
例如,您可以说:
let x = +5
所以只想说:
let plus: (Int, Int) -> Int = +
混淆了编译器,因为它将 +
视为一元前缀运算符,并且它期望 +
后跟其他内容,例如 5
。通过用括号括起来,Swift 编译器然后停止尝试将 +
解析为一元运算符,并将其视为函数名称。即使 +
不是一元前缀运算符,Swift 仍然期望 +
两边的值,所以括号告诉 Swift 你不是为函数提供任何输入,但只需要函数本身。
在没有歧义的情况下,您可以引用不带括号的 +
函数。例如:
var arr = [1, 2, 3]
let sum = arr.reduce(0, +)
(+)
本身就是一个运算符方法。您可以像这样声明自己的运算符:
precedencegroup CompositionPrecedence {
associativity: left
higherThan: AssignmentPrecedence
}
infix operator •: CompositionPrecedence
func •(a: Int, b: Int) -> Int {
return a + b
}
用法相同:
var closure: (Int, Int) -> Int = (•)
print("\(closure(1, 2))")
我在
let plus: (Int, Int) -> Int = (+)
我理解左侧 — 它声明了一个 (Int, Int) -> Int
类型的常量(一个接受两个整数和 returns 一个整数的函数)。但是 (+)
是什么?它如何声明一个没有大括号的函数,当没有任何类型的参数标签时它如何引用两个参数?
该函数接受两个参数,将它们相加,returns 结果。如果我将 +
运算符替换为不同的运算符(比如 *
),则操作会发生变化。那么它是某种 shorthand 用于 {[=15=] + }
吗?如果是这样,这shorthand背后的逻辑是什么?
其实这不是shorthand。
plus
是 (Int, Int) -> Int
类型的变量。您可以将任何属于此类型(或其任何子类型)的对象分配给它。文字 lambda 闭包当然是这种类型,但实际上命名函数或方法也可以。这正是这里正在发生的事情。
正在将名为+
的运算符方法对象赋值给变量。
这在 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: >)
因此,代码所做的是将 运算符方法 +
分配给变量 plus
。 +
只是分配给变量的函数的名称。没有魔法 shorthand 涉及。
看到这个你会不会很惊讶?
let plus: (Int, Int) -> Int = foo
+
是 infix
运算符和 Swift 中的 函数名 。在许多类型上定义了许多这样的函数(它被重载了)。
您可以为自己的自定义类型定义 +
。例如:
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
这个有效:
let plus: (Int, Int) -> Int = (+)
因为+
函数的签名已经完全指定,所以Swift能够识别正确的+
函数。
如果我们想将新的 +
函数分配给 plus
:
let plus: (Foo, Foo) -> Foo = (+)
真的和这个没什么区别:
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+
?
+
也是 Swift.
例如,您可以说:
let x = +5
所以只想说:
let plus: (Int, Int) -> Int = +
混淆了编译器,因为它将 +
视为一元前缀运算符,并且它期望 +
后跟其他内容,例如 5
。通过用括号括起来,Swift 编译器然后停止尝试将 +
解析为一元运算符,并将其视为函数名称。即使 +
不是一元前缀运算符,Swift 仍然期望 +
两边的值,所以括号告诉 Swift 你不是为函数提供任何输入,但只需要函数本身。
在没有歧义的情况下,您可以引用不带括号的 +
函数。例如:
var arr = [1, 2, 3]
let sum = arr.reduce(0, +)
(+)
本身就是一个运算符方法。您可以像这样声明自己的运算符:
precedencegroup CompositionPrecedence {
associativity: left
higherThan: AssignmentPrecedence
}
infix operator •: CompositionPrecedence
func •(a: Int, b: Int) -> Int {
return a + b
}
用法相同:
var closure: (Int, Int) -> Int = (•)
print("\(closure(1, 2))")