在 Swift 中使用可选项迭代数组的结果令人惊讶

Surprise results iterating over an array with an optional in Swift

令我惊讶的是这段 swift 代码表现得很好:

let values = ["Hello", "Test"]

var count = 0
for string: String in values {
    count = count + 1
    print("count is: ", count)
    print(string)
} 

输出为:

count is:  1
Hello
count is:  2
Test

但是把字符串变成字符串?创建一个无限循环。

   let values = ["Hello", "Test"]

    var count = 0
    for string: String? in values {
        count = count + 1
        print("count is: ", count)
        print(string)
    }

输出为:

count is:  1
Optional("Hello")
count is:  2
Optional("Test")
count is:  3
nil
count is:  4
nil
count is:  5
nil
count is:  6
nil
count is:  7
nil
count is:  8
(ad infinitum)

Swift 非常擅长捕捉奇怪的代码问题,我很惊讶我可以在没有警告或错误的情况下走进这样一个烂摊子。 这真的是人们对 Swift 4 的期望吗?如果是,为什么?

您的 "for" 在索引上运行。索引下超过元素个数为nill。

没有错误。在第一个函数中,它将继续运行直到不再有字符串。

但另一方面,您将字符串设置为可选的第二个函数,因此当它不再有字符串时,它仍会继续运行。因为 nil 是一个 nil 值,它不等于没有。你没有任何东西可以结束那个循环。

为了理解这个问题,回忆一下 for-in 循环是如何工作的:

for s in values {
    print(s)
}

创建序列的迭代器,并调用迭代器的next()方法直到returns nil:

var it = values.makeIterator()
while let s = it.next() {
    print(s)
}

你的第二个版本相当于

var it = values.makeIterator()
while let s: String? = it.next() {
    print(s)
}

现在编译器警告:

warning: explicitly specified type 'String?' adds an additional level
of optional to the initializer, making the optional check always succeed
    while let s: String? = it.next() {
          ^      ~~~~~~~   ~~~~~~~~~
                 String

所以这里发生的是 String?it.next() 返回 被包装成 String?? 类型的“嵌套可选”.some(it.next()),然后可选地绑定到 s: String?。 这总是成功的,因为 .some(it.next()) 不是 String??.none。 因此循环永远不会终止。

有人可能会争辩说编译器也应该对

发出警告
for s: String? in values {
    print(s)
}