Структура копируется
Вернёмся к ксероксу из начала темы. Бланк Point с x: 1 кладут в копировальный аппарат и получают копию. На копии графу x исправляют на 10. Оригинал при этом не меняется: в нём по-прежнему x: 1.
Структура в Swift копируется так же. Посмотрим на код:
struct Point {
var x: Int
var y: Int
}
let a = Point(x: 1, y: 2)
var b = a
b.x = 10
print(a.x, b.x) // 1 10Давайте разберём программу по строкам:
let a = Point(x: 1, y: 2)заполняет бланк-оригинал.var b = aделает копию: теперь бланков два, и записи на них одинаковые.b.x = 10исправляет графу только на копии.print(a.x, b.x)печатает1 10: оригинал не изменился.
Обратите внимание: a объявлен через let, а b — через var. У копии своё объявление, поэтому её можно менять, хотя оригинал — константа.
Структура — значимый тип
Как вы уже знаете, массив — значимый тип: присваивание создаёт его независимую копию. Структура тоже значимый тип. Чаще всего её копия появляется в двух случаях:
- при присваивании:
var b = a; - при передаче в функцию: параметр получает свою копию экземпляра.
Нажмите «Следующий шаг» и сравнивайте a с b, а потом b с точками внутри функции moved: меняется только тот экземпляр, у которого исправили свойство.
1struct Point {2 var x: Int3 var y: Int4}5 6func moved(_ p: Point) -> Point {7 var copy = p8 copy.x += 59 return copy10}11 12let a = Point(x: 1, y: 2)13var b = a14b.x = 1015print(a.x, b.x)16let c = moved(b)17print(b.x, c.x)
Константа a — бланк-оригинал с x: 1 и y: 2.
Функция moved получает копию b в параметр p. Параметр — константа, поэтому функция делает ещё одну копию, copy, меняет её и возвращает. После вызова b прежний, а точка с x: 15 лежит в c. Чтобы функция изменила саму переменную того, кто её вызвал, нужны параметр inout и & при вызове.
Здесь картинка с ксероксом неточна. Бумажную копию делают вручную, когда она нужна. Swift копирует структуру сам, при каждом присваивании и передаче в функцию, без отдельной команды «скопировать».
На собеседовании часто спрашивают: что станет с первой структурой, если изменить её копию? Ответ: ничего. Структура — значимый тип, и у копии свои свойства, независимые от оригинала.
Частая ошибка
Точку достали из массива, изменили и ждали, что изменится элемент массива:
var points = [Point(x: 1, y: 2), Point(x: 3, y: 4)]
var first = points[0]
first.x = 10 // ✗
print(points[0].x) // 1Программа компилируется и печатает 1. Строка var first = points[0] создаёт копию элемента, и first.x = 10 исправляет только её, а элемент в массиве остался прежним. Чтобы изменить сам элемент, пишите через индекс: points[0].x = 10.
Главное
- Структура — значимый тип:
var b = aсоздаёт независимую копию, и измененияbне видны вa. - У копии своё объявление: структуру из
letможно скопировать вvarи менять. - Функция получает свою копию структуры, и изменения внутри функции не трогают переменную снаружи.
- Переменная получает копию элемента массива; сам элемент меняют через индекс:
points[0].x = 10.