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

时间:2018-11-02 19:26:46

标签: swift swift4

我很惊讶这个快速的代码表现得很好:

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

但是将String变成String?创建一个无限循环。

   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的期望吗?如果是这样,为什么?

3 个答案:

答案 0 :(得分:7)

要了解此问题,有助于重新了解for-in循环的工作方式:

for s in values {
    print(s)
}

创建序列的 iterator ,并调用迭代器的next()方法,直到返回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() 被包装到类型为.some(it.next())的“嵌套可选” String??中,然后可选地绑定到s: String?。 因为.some(it.next())不是String??.none,所以它总是会成功。 因此循环永远不会终止。

有人可能会认为编译器也应针对

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

答案 1 :(得分:0)

您的“ for”在索引上运行。在索引下,超出元素数的位置为零。

答案 2 :(得分:0)

没有错误。在第一个函数中,它将继续进行直到没有更多的字符串为止。

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