Цикл for in проходит через копию последовательности?

В книге Мэтта Нойбурга iOS 13 Programming Fundamentals with Swift я наткнулся на следующие утверждения:

Когда вы прокручиваете последовательность с помощью for...in, вы на самом деле прокручиваете копию последовательности. Это означает, что безопасно изменять последовательность, пока вы прокручиваете ее:

И автор привел следующий пример для приведенных выше утверждений:

var s : Set = [1,2,3,4,5]
for i in s {
    if i.isMultiple(of:2) {
        s.remove(i)
    }
} // s is now [1,3,5]

В приведенном выше примере мы видим, что исходный массив был изменен с [1,2,3,4,5,6] на [1,3,5]. Это означает, что сам массив был изменен. Таким образом, цикл for in обрабатывал не копию исходного массива, а сам массив. Это, кажется, противоречит заявлениям автора выше.

Так что я не уверен, верны утверждения автора или нет. Кто-нибудь, пожалуйста, проясните этот вопрос? Большое спасибо.


person Michael May    schedule 06.07.2020    source источник
comment
Если бы он не зацикливался на копии, как только вы начали удалять элементы, весь цикл пошел бы не так, как надо, и приложение вылетело бы из строя. Например, вы можете проверить, что произойдет в Objective C.   -  person user28434'mstep    schedule 06.07.2020
comment
Конечно, s.remove(i) удаляет элемент из множества s...   -  person Martin R    schedule 06.07.2020
comment
Связано: Удалить элемент из коллекции во время итерации с forEach.   -  person Martin R    schedule 06.07.2020


Ответы (2)


Формулировка может на первый взгляд немного ввести в заблуждение, но утверждение, что for i in s повторяет копию исходного s, верно. Если бы это было не так, вы бы получили исключение за пределами границ или неожиданный результат (некоторые элементы коллекции были бы пропущены), поскольку вы изменяли бы коллекцию во время ее повторения.

Когда вы создаете цикл с for i in s, создается копия s, и итерация происходит через эту копию. Однако, когда вы получаете доступ к s внутри тела цикла, вы получаете доступ к исходному s и, следовательно, изменяете его, а не изменяете копию, которую повторяет цикл.

person Dávid Pásztor    schedule 06.07.2020

Здесь есть небольшой нюанс. Массив, который вы повторяете, является копией, но массив, который вы изменяете, по-прежнему остается оригиналом.

В других случаях этот код пропустит несколько элементов из-за изменения индекса.

Если это не так, то рассмотрим следующие итерации

// i = 0
// s = [1,2,3,4,5]
// evaluation 1.isMultiple(of: 2)
// element to be removed: none
// i = 1
// s = [1,2,3,4,5]
// evaluation 2.isMultiple(of: 2)
// element to be removed: 2
// Here is where the problems would start, since the number 3 would be skipped.
// i = 2
// s = [1,3,4,5]
// evaluation 4.isMultiple(of: 2)
// element to be removed: 2

Поскольку вы повторяете копию, вы можете изменить s и при этом убедиться, что все элементы будут учтены.

person Daniel Barden    schedule 06.07.2020