Сюрприз результаты итерации по массиву с необязательным в Swift - PullRequest
0 голосов
/ 02 ноября 2018

Я был удивлен, что этот быстрый код ведет себя хорошо:

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? И если да, то почему?

Ответы [ 3 ]

0 голосов
/ 02 ноября 2018

Нет ошибок. В первой функции он будет работать до тех пор, пока не останется строк.

Но, с другой стороны, во второй функции вы устанавливаете строку как необязательную, поэтому, когда строки больше нет, она все равно будет продолжать работать. Потому что ноль - это ноль, и это не то же самое, что ничто. У вас нет ничего, что заканчивает этот цикл.

0 голосов
/ 02 ноября 2018

Чтобы понять эту проблему, полезно вспомнить, как работают циклы for-in:

for s in values {
    print(s)
}

создает итератор последовательности и вызывает метод итератора 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)
}
0 голосов
/ 02 ноября 2018

Ваше "для" работает по индексам. Под индексом превышающим количество элементов стоит ноль.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...