为什么在Swift的单个返回表达式中使用闭包速记命名变量必须是详尽无遗的?

时间:2017-03-26 22:10:55

标签: swift swift3 closures

以下一段代码在Swift中是错误的。

func foo(closure: (Int, Int) -> Int) -> Int {
    return closure(1, 2)
}

print(foo(closure: {$0}))
func foo(closure: (Int, Int) -> Int) -> Int {
    return closure(1, 2)
}

print(foo(closure: {return $0}))

XCode playground提供的错误是无法转换'(Int, Int)' to closure result type 'Int'类型的值。

虽然以下几段代码完全正常。

func foo(closure: (Int, Int) -> Int) -> Int {
    return closure(1, 2)
}

print(foo(closure: {$0 + $1}))
func foo(closure: (Int, Int) -> Int) -> Int {
return closure(1, 2)
}
print(foo(closure: {$1; return $0}))
func foo(closure: (Int, Int) -> Int) -> Int {
    return closure(1, 2)
}

print(foo(closure: {a, b in a}))

似乎在闭包的参数由缩写参数名称引用的情况下,如果闭包的主体只包含返回表达式,则必须使用它们。为什么呢?

2 个答案:

答案 0 :(得分:2)

你的“为什么”就像问“为什么美式足球场长100码?”这是因为那些是规则。接受参数的匿名函数体必须明确确认所有参数。它可以通过以下三种方式执行此操作:

  • 使用$0$1,...表示法代表他们。

  • 使用in行中的参数名称表示它们。

  • _行中使用in明确弃置它们。

所以,让我们看一个比你更简单的例子:

func f(_ ff:(Int)->(Void)) {} 

如您所见,函数f采用一个参数,这是一个带一个参数的函数。

那么,让我们尝试将一些匿名函数交给f

这是合法的,因为我们将参数命名为in行:

f {
    myParam in
}

这是合法的,因为我们使用$0表示法接受参数:

f {
    $0
}

这是合法的,因为我们在_行中使用in明确地丢弃了参数:

f {
    _ in
}

但这不合法:

f {
    1 // error: contextual type for closure argument list expects 1 argument, 
    // which cannot be implicitly ignored
}

答案 1 :(得分:2)

如果你只使用$0,假设闭包参数是一个元组而不是多个变量$0$1等等。所以你应该能够解决这个问题该元组的第一个值:

print(foo(closure: {$0.0}))