在for-in循环中使用尾随闭包

Muh*_*san 10 swift swift2

我正在使用map()for-in循环中的数组函数,如下所示:

let numbers = [2, 4, 6, 8, 10]

for doubled in numbers.map { $0 * 2 } // compile error
{
    print(doubled)
}
Run Code Online (Sandbox Code Playgroud)

这会产生编译错误:

使用未解析的标识符'doubled'

但是,如果我将括号用于map()函数,它可以正常工作.即

for doubled in numbers.map ({ $0 * 2 })
{
    print(doubled)
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,为什么编译器不会区分尾随函数和循环的代码块,假设这会导致问题?

Lew*_*Lew 9

这是因为尾随函数应该运行的上下文存在歧义.另一种有效的语法是:

let numbers = [2, 4, 6, 8, 10]

for doubled in (numbers.map { $0 * 2 }) // All good :)
{
    print(doubled)
}
Run Code Online (Sandbox Code Playgroud)

我想这可能是因为'in'运算符的优先级高于尾随函数.

您认为更具可读性取决于您.


das*_*ght 8

尾随关闭语法生成声明的主体之间的已知不确定性(在你的情况,这是for循环的,但它也适用于其他报表以及)和尾部封闭的身体.虽然在技术上可以解决这个问题,但编译器设计者决定在控制各种高级语句的部分时禁止使用尾随闭包语法:

虽然通过执行任意前瞻或通过在解析时执行类型检查来判断在某些情况下的意图是可能的,但这些方法对编译器的体系结构具有显着影响.因此,我们选择保持解析器简单并且不允许这样做.

要了解冲突的性质,请考虑以下示例:

for v in expr { /* code 1 */ } { /* code 2 */ }
Run Code Online (Sandbox Code Playgroud)

解析器需要对code 1块进行选择.这既可以把它作为一个尾随关闭expr和治疗code 2为主体for循环,或使用code 1作为体for循环,而治疗code 2的花括号中的语句的一个独立小组-一个经典的移减少冲突.

解决此类冲突非常昂贵.从本质上讲,您的解析器需要继续展望更多令牌,直到只有一种解释有意义,或者解析器耗尽令牌(在这种情况下,它会以某种方式做出任意决定,要求程序员在解决其程序时消除歧义那个选择不是他们想要的.

添加括号可消除歧义.提议被认为通过添加强制关键字来消除歧义,以将循环的控制部分与其主体分开,即

// The syntax of rejected proposal
for doubled in numbers.map { $0 * 2 } do {
    print(doubled) //                 ^^
}
Run Code Online (Sandbox Code Playgroud)

添加一个额外的do关键字"附加"左边的块(如果有的话)到表达式,并使右边的块成为循环语句的主体.这种方法有一个主要缺点,因为它是一个突破性的变化.这就是为什么这个提案被拒绝了.