为啥在 Swift 的单数返回表达式中使用闭包简写变量必须详尽无遗?

Posted

技术标签:

【中文标题】为啥在 Swift 的单数返回表达式中使用闭包简写变量必须详尽无遗?【英文标题】:Why does use of closure shorthand-named variables has to be exhaustive in a singular return expression in Swift?为什么在 Swift 的单数返回表达式中使用闭包简写变量必须详尽无遗? 【发布时间】:2017-03-26 22:10:55 【问题描述】:

以下代码在 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 给出的错误是Cannot convert value of type '(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))

似乎在闭包的参数由速记参数名称引用的情况下,如果闭包的主体仅由返回表达式组成,则必须彻底使用它们。为什么?

【问题讨论】:

相关:Why is the shorthand argument name $0 returning a tuple of all parameters?. 【参考方案1】:

如果您只使用$0,则假定闭包参数是一个元组而不是多个变量$0$1 等。因此您应该能够通过提取该元组的第一个值来解决此问题:

print(foo(closure: $0.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

【讨论】:

问问题的原因难道不是隐藏规则,而不是规则吗?我相信我们都希望 Swift 的设计是有道理的 ;-) @CRD 就像 Swift 的许多规则一样,这一切都是为了让您明确承认自己知道自己在做什么。考虑override;它什么也没增加(因为 Objective-C 不使用它),所以如果你覆盖一个继承的成员,“为什么”需要它?为了让你明确。 我认为您误解了我的评论,可能还不够清楚。实际上,我认为这与 Swift 中类型推断的工作方式有关(参见@Palle 的回答),这就是“为什么”——而不是因为它是规则。类型推断不必以这种方式工作,一种不同的方法可以支持 OP 的预期(但可能不是 Swift 所做的其他事情——这都是关于选择的)。 OP 提出了一个合理的问题。

以上是关于为啥在 Swift 的单数返回表达式中使用闭包简写变量必须详尽无遗?的主要内容,如果未能解决你的问题,请参考以下文章

简写的闭包数组:Xcode Swift:表达式太复杂,无法在合理的时间内解决

理解 Swift 中 map 函数的简写闭包语法

为啥 Swift 不更新闭包外的变量?

Swift学习笔记:闭包

PromiseKit ios Swift 闭包返回类型问题

Swift系列八