我在for-in循环中使用map()
数组函数,如下所示:
let numbers = [2, 4, 6, 8, 10]
for doubled in numbers.map { $0 * 2 } // compile error
{
print(doubled)
}
产生编译错误:
使用未解析的标识符'加倍'
但是,如果我为map()
函数添加括号,它可以正常工作。即。
for doubled in numbers.map ({ $0 * 2 })
{
print(doubled)
}
我的问题是,为什么编译器不会区分尾随函数和循环的代码块,假设这会导致问题?
答案 0 :(得分:9)
这是因为尾随函数应该运行的上下文存在歧义。另一种有效的语法是:
let numbers = [2, 4, 6, 8, 10]
for doubled in (numbers.map { $0 * 2 }) // All good :)
{
print(doubled)
}
我想这可能是因为'in'运算符的优先级高于尾随函数。
您认为更具可读性取决于您。
答案 1 :(得分:8)
尾随闭包语法在语句的主体(在您的情况下,该for
循环中,但它也适用于其他语句)和尾随闭包的主体之间产生已知的歧义。虽然技术上可以解决此问题,但compiler designers decided to prohibit trailing closure syntax in controlling portions of various high-level statements:
虽然可以通过执行任意前瞻或通过在解析时执行类型检查来判断在某些情况下的目的是什么,但这些方法对编译器的体系结构具有显着影响。因此,我们选择保持解析器简单并且不允许这样做。
要了解冲突的性质,请考虑以下示例:
for v in expr { /* code 1 */ } { /* code 2 */ }
解析器需要对code 1
块做出选择。它可以将它用作expr
的尾随闭包,并将code 2
视为for
循环的主体,或使用code 1
作为for
的正文}循环,同时将code 2
视为用大括号括起来的独立语句组 - 经典shift-reduce conflict。
解决此类冲突非常昂贵。从本质上讲,您的解析器需要继续展望更多令牌,直到只有一种解释有意义,或者解析器耗尽令牌(在这种情况下,它会以某种方式做出任意决定,要求程序员在解决其程序时消除歧义那个选择不是他们想要的。)
添加括号可消除歧义。提议被认为通过添加强制性关键字来消除歧义,以将循环的控制部分与其主体分开,即
// The syntax of rejected proposal
for doubled in numbers.map { $0 * 2 } do {
print(doubled) // ^^
}
添加额外的do
关键字"附加"左边的块,如果有的话,到表达式,并使右边的块成为循环语句的主体。这种方法有一个主要缺点,因为它是一个突破性的变化。这就是为什么这个提案被拒绝了。
答案 2 :(得分:2)
语法不明确(参见dasblinkenlight's answer)。对于替代语法:
let numbers = [2, 4, 6, 8, 10]
numbers.map { $0 * 2 }.forEach {
print(doubled)
}
或
let numbers = [2, 4, 6, 8, 10]
let doubledNumbers = numbers.map { $0 * 2 }
for doubled in doubledNumbers {
print(doubled)
}