没有花括号和没有参数标签的匿名函数?

问题描述 投票:2回答:3

我在another question上看到了一些代码,它们似乎创建了一个带有一些不寻常语法的匿名函数(闭包表达式):

let plus: (Int, Int) -> Int = (+)

我理解左侧 - 它声明了一个(Int, Int) -> Int类型的常量(一个带两个整数并返回一个整数的函数)。但(+)是什么?如何在没有大括号的情况下声明一个函数,当没有任何类型的参数标签时,它如何引用这两个参数?

该函数接受两个参数,将它们相加,然后返回结果。如果我用另一个(例如+)替换*运算符,则操作会更改。那么它是{$0 + $1}的某种简写吗?如果是这样,这个速记背后的逻辑是什么?

swift lambda anonymous-function shorthand
3个回答
2
投票

实际上,这不是速记。

plus(Int, Int) -> Int类型的变量。您可以为其指定此类型(或其任何子类型)的任何对象。文字lambda闭包肯定是这种类型,但实际上命名函数或方法也可以。而这正是这里发生的事情。

它将名为+的运算符方法对象赋给变量。

Closures chapter of the language guide中隐含地提到了这种情况:

Operator Methods

实际上有一种更短的方式来编写上面的闭包表达式。 Swift的String类型将其大于运算符(>)的字符串特定实现定义为具有String类型的两个参数的方法,并返回类型为Bool的值。这与sorted(by:)方法所需的方法类型完全匹配。因此,您可以简单地传入大于运算符,Swift将推断您要使用其特定于字符串的实现:

reversedNames = names.sorted(by: >)

因此,代码正在做的是将操作符方法+分配给变量plus+只是分配给变量的函数的名称。没有任何神奇的速记。

你会惊讶地看到这个吗?

let plus: (Int, Int) -> Int = foo

2
投票

+是一个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

括号为什么呢?为什么要指定(+)而不仅仅是+

+也是斯威夫特的一元运营商。

例如,您可以说:

let x = +5

所以试着说:

let plus: (Int, Int) -> Int = +

混淆编译器,因为它将+视为一元前缀运算符,并期望+后跟其他东西,如5。通过用括号括起来,Swift编译器然后停止尝试将+解析为一元运算符,并将其视为函数名称。即使+不是一元前缀运算符,Swift仍然期望+两侧的值,所以括号告诉Swift你没有为函数提供任何输入,但只想要函数本身。

在不明确的情况下,您可以参考没有括号的+函数。例如:

var arr = [1, 2, 3]
let sum = arr.reduce(0, +)

2
投票

(+)本身就是一种算子方法。您可以像这样声明自己的运算符:

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))")
© www.soinside.com 2019 - 2024. All rights reserved.