是否存在 "for _ in [1,2,3]" 根本不会循环的*任何*情况?

Is there *any* situation under which "for _ in [1,2,3]" will not loop at all?

我在写一些代码时犯了一个错误,简化为:

func f() -> Int {
    for _ in [1,2,3] {
        return 1
    }
}

并且编译器向我显示一个错误,指出 f 缺少一个 return,这让我意识到我的错误。我忘了在 return!

周围加上 if 语句

但后来我发现编译器其实在撒谎!该函数将始终 return一个值。或者会吗?有没有for循环不循环的情况?

我问这个是因为其他重言式结构编译得很好:

if 1 < 2 {
    return 1
}

while true {
    return 1
}

而且我还了解到编译器无法在编译时评估 每个 表达式以查看它们是否是重言式。我知道属性访问和方法调用通常不会在编译时进行评估,因此预计不会编译:

if "".isEmpty {
    return 1
}

但通常文字是可以的,对吧?毕竟,编译器必须评估文字 [1,2,3] 才能将其翻译成表示 "create an array with 1, 2, 3".

的机器代码

那么为什么搞清楚for循环还不够聪明呢?在某些罕见的情况下,for 循环不会得到 运行 吗?

虽然对于人类来说,看到循环总是重复三次是微不足道的,因为列表文字是一个包含三个元素的常量,但对于处于语义分析。

在进行语义分析时,编译器会计算"a generic list literal"([1,2,3])并确定它是Array<Int>类型的表达式。但是现在,当然,这是一个常量或这个数组包含三个元素的信息丢失了。

语义分析通常使用程序员正在使用的相同(或非常相似)的类型系统来执行。由于与成本相比,将数组中的元素数量附加到类型(元素数量通常在编译时未知)几乎没有什么好处,因此通常不会这样做。另一方面,常量折叠 (if 1 < 2 {) 更容易实现并且更频繁地出现。

虽然在较低级别上,编译器可能会展开此循环并使用常量值,但这种情况发生的时间要晚得多 – 在 Swift 中生成 Swift 中间语言表示之后 – 可能只是在代码生成期间——在 SIL 被发送到 LLVM IR 之后,当 LLVM 优化为 运行.

for-in 不知道它要从迭代器中获得的全部是 nil。无论序列是什么,您都会收到相同的错误消息 Missing return in a function expected to return 'Int'

extension Bool: Sequence, IteratorProtocol {
  public func next() -> Void? { () }
}
for _ in true {