Будет ли изменение ArraySlice создавать новый экземпляр массива?

var absences = [0, 2, 0, 4, 0, 3, 1, 0]
let midpoint = absences.count / 2

var firstHalf = absences.prefix(upTo: midpoint)
let secondHalf = absences.suffix(from: midpoint)

Цитата от Apple:

Ни срезы firstHalf, ни secondHalf не выделяют никакого собственного нового хранилища. Вместо этого каждый представляет представление о хранении массива отсутствий.

Когда я пытаюсь изменить firstHalf следующим образом:

firstHalf[1] = 19

значения firstHalf меняются, но исходный массив absences остается прежним (firstHalf[1] равно 19, а absences[1] равно 2) Итак, что происходит в фоновом режиме. Создал ли я экземпляр нового массива, изменив срез массива? Заранее спасибо.


person Pink    schedule 24.04.2017    source источник
comment
Вероятно, это типичное поведение копирования при записи, используемое за кулисами коллекциями Swift, когда коллекция не копируется до тех пор, пока вы не попытаетесь изменить ее. Обсуждение копирования при записи см. в видеоролике WWDC 2015 Создание лучших приложений с помощью типов значений .   -  person Rob    schedule 24.04.2017
comment
Вот что тоже пришло мне в голову. Я просто хочу быть в этом уверен. Спасибо за быстрый ответ.   -  person Pink    schedule 24.04.2017


Ответы (2)


Да, все типы коллекций стандартной библиотеки, включая Array и ArraySlice, имеют поведение копирования при записи. Это означает, что они могут совместно хранить свои элементы с другими коллекциями до тех пор, пока они не будут видоизменены, и в этом случае они получат свою собственную копию.

В вашем случае базовый буфер массива, на который срез firstHalf имеет представление, не имеет уникальной ссылки (поскольку и absences, и secondHalf также имеют представление о нем). Поэтому, когда вы переходите к изменению firstHalf, запускается копирование — создается новый буфер, содержащий элементы среза (но не обязательно весь массив).

firstHalf теперь имеет уникальный вид на этот новый буфер, а absences и secondHalf оба имеют общий вид на старый буфер массива. Поэтому firstHalf теперь может изменять элементы своего буфера, не затрагивая элементы исходного массива, тем самым сохраняя семантику значений.

person Hamish    schedule 24.04.2017

Это стандартное поведение копирования при записи, используемое за кулисами коллекциями Swift, когда коллекция не копируется до тех пор, пока вы не попытаетесь изменить ее. Обсуждение копирования при записи см. в видеоролике WWDC 2015 Создание лучших приложений с помощью типов значений в Свифте.

Комментарии в коде разъясняют это для нас:

/// Slices Share Indices
/// --------------------
///
/// A collection and its slices share the same indices. An element of a
/// collection is located under the same index in a slice as in the base
/// collection, as long as neither the collection nor the slice has been
/// mutated since the slice was created.

...

/// Slices Inherit Collection Semantics
/// -----------------------------------
///
/// A slice inherits the value or reference semantics of its base collection.
/// That is, when working with a slice of a mutable
/// collection that has value semantics, such as an array, mutating the
/// original collection triggers a copy of that collection, and does not
/// affect the contents of the slice.
person Rob    schedule 24.04.2017
comment
Идеальный! Спасибо. Хотя я уже принял ответ Харниша, было бы несправедливо изменить это ^^ - person Pink; 24.04.2017
comment
@Pink Я бы не стал просить вас изменить принятый ответ. Я просто предоставлял подтверждающую документацию относительно предыдущего комментария. - person Rob; 24.04.2017
comment
Тогда нет проблем. Ваше здоровье! - person Pink; 24.04.2017
comment
@Pink Обратите внимание, что вы можете изменить принятый ответ на тот, который, по вашему мнению, лучше всего отвечает на ваш вопрос — определенно не несправедливо изменить отметку о принятии на более поздний ответ, если вы считаете, что он лучше :) - person Hamish; 24.04.2017