Перейти к содержимому
Теория · Массивы · урок 2 из 8

Изменение массива

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

Массив, объявленный через var, умеет то же самое. Эта программа меняет ряд оценок четыре раза и печатает его после каждого изменения:

SWIFT
var scores = [7, 9]
scores.append(4)
print(scores)  // [7, 9, 4]
scores.insert(10, at: 0)
print(scores)  // [10, 7, 9, 4]
let removed = scores.remove(at: 1)
print(removed, scores)  // 7 [10, 9, 4]
scores[0] = 8
print(scores)  // [8, 9, 4]

Давайте разберём, что делает каждое изменение:

  1. append(4) добавляет 4 в конец, и массив становится [7, 9, 4].
  2. insert(10, at: 0) вставляет 10 по индексу 0, а остальные элементы сдвигаются вправо.
  3. remove(at: 1) убирает элемент с индексом 1 — это 7 — и возвращает его, поэтому 7 попадает в константу removed.
  4. scores[0] = 8 кладёт 8 на место 10.

append, insert и remove — методы массива: их вызывают через точку после имени массива, как методы строк.

Четыре способа изменить массив

append — в конец

scores.append(4) добавляет элемент после последнего. count вырастает на единицу, а индексы старых элементов не меняются.

insert(_:at:) — по индексу

scores.insert(10, at: 0) ставит элемент на место с индексом 0. Все элементы с этого места сдвигаются на одну позицию вправо: 7 был по индексу 0, а стал по индексу 1. Индекс для вставки берут от 0 до count, и вставка по индексу count работает как append.

remove(at:) — убрать

scores.remove(at: 1) убирает элемент, и элементы справа от него сдвигаются влево, чтобы в ряду не осталось дыры. Метод возвращает удалённое значение: его можно сохранить, как removed в примере, а можно не использовать.

Присваивание по индексу

scores[0] = 8 заменяет элемент, а число элементов остаётся прежним. Так меняют только элемент, который уже есть. Индекс за границами массива и здесь, и в remove(at:) аварийно завершает программу.

Здесь картинка со шкафчиками неточна. На дверце шкафчика номер написан раз и навсегда, а в массиве после insert и remove индексы пересчитываются. Они всегда идут подряд, от 0 до count - 1.

Склейка через +

Оператор + склеивает два массива одного типа в новый массив. Исходные массивы он не меняет:

SWIFT
let more = scores + [5, 6]
print(scores.count, more.count)  // 3 5

В scores по-прежнему три элемента, а в новом массиве more — пять. Поэтому + работает и с массивами, объявленными через let.

Частая ошибка

Элемент добавили в массив, объявленный через let:

SWIFT
let days = [1, 2, 3]
days.append(4) // ✗
TEXT
error: cannot use mutating member on immutable value: 'days' is a 'let' constant

Программа не компилируется. Массив через let — константа целиком: в нём нельзя добавить, вставить, удалить или заменить ни одного элемента. Замена по индексу даёт похожую ошибку: cannot assign through subscript: 'days' is a 'let' constant. Если ряд должен меняться, объявите его через var.

На собеседовании часто спрашивают, можно ли изменить массив, объявленный через let. Например, в JavaScript константа запрещает только связать имя с другим массивом, а сам массив менять можно. В Swift let замораживает и содержимое.

Главное

  • append добавляет в конец, insert(_:at:) вставляет по индексу, а remove(at:) удаляет элемент и возвращает его.
  • После вставки и удаления индексы пересчитываются и снова идут подряд с нуля.
  • + создаёт новый массив и не меняет исходные.
  • Массив через let менять нельзя: ни добавить, ни удалить, ни заменить элемент.