Ответ
Нет, не всегда. Swift стремится избегать излишних копий для повышения эффективности, сохраняя при этом гарантии value-семантики.
Что происходит на самом деле:
- Логическое копирование происходит сразу. Две переменные становятся независимыми с точки зрения языка.
- Физическое копирование данных откладывается до первой модификации одной из копий благодаря Copy-on-Write (CoW).
Пример с CoW:
struct LargeStruct { var data: [Int] = Array(1...1000) }
var a = LargeStruct()
var b = a // Логическая копия. Физически `a.data` и `b.data`
// могут указывать на один массив в памяти (нет копирования 1000 элементов).
b.data.append(1001) // ТЕПЕРЬ, при модификации `b`, происходит реальное
// копирование внутреннего массива (`data`).
Оптимизации компилятора: Для простых, небольших структур (например, Point с двумя Int) компилятор может пропустить даже логическую отложенность и выполнить копирование сразу, так как это дешево.
Вывод: Swift гарантирует семантику копирования по значению (изменение одной копии не влияет на другую), но реализация использует оптимизации (CoW), чтобы физическое копирование происходило только при необходимости.
Ответ 18+ 🔞
А, слушай, тут народ часто путается, как эти ваши структуры в Свифте копируются. Думают, что каждый раз, когда присваиваешь, начинается пиздец — весь массив по байтику перетаскивается. Ну, блядь, не всегда же!
Что на самом деле творится, ёпта:
- Копия по документам создаётся мгновенно. Для языка ты получил две независимые сущности, и хуй с ним.
- А вот реальное копирование данных в памяти откладывается до последнего, пока ты одну из копий не начнёшь трогать. Это и есть та самая хитрая жопа под названием Copy-on-Write (CoW).
Смотри, как это выглядит в деле:
struct LargeStruct { var data: [Int] = Array(1...1000) }
var a = LargeStruct()
var b = a // Вот тут, блядь, логически скопировали. А физически `a.data` и `b.data`
// могут спокойно тыкать в один и тот же массив в памяти. Никаких 1000 элементов не копируется, овердохуища экономия!
b.data.append(1001) // А ВОТ ТУТ, сука, когда ты полез в `b` и начал менять, — вот тогда-то и происходит реальное,
// полномасштабное копирование внутреннего массива (`data`). Чих-пых тебя в сраку, оптимизация!
Ещё один фокус: Для простеньких структур, вроде точки с парой Int, компилятор может вообще не париться с этой отложенностью и скопировать всё сразу — ибо дешево, блядь.
Короче, вывод: Свифт гарантирует тебе поведение как при копировании по значению — потрогал одну копию, другая не дернулась. Но под капотом он не мудак, и использует оптимизации (ту самую CoW), чтобы реально копировать память только тогда, когда без этого уже совсем никак, нахуй.