История вопроса:
Subscript — это механизм обращения к значениям внутри коллекций, структур и других типов с помощью квадратных скобок. Он добавлен в Swift по аналогии с другими языками (например, индексация в массивах Python, оператор [] в C++/Java), чтобы сделать работу с коллекциями и подобными объектами более интуитивной.
Проблема:
Не все типы по умолчанию поддерживают обращение по индексу как массив. Когда у нас есть структура или класс с данными, доступ к элементам часто логичнее реализовать через привычный синтаксис (типа myObject[index]), а не методом.
Решение:
Swift позволяет реализовать subscript самостоятельно для любого пользовательского типа. Можно сделать его как для чтения, так и для записи. Пример — структура, реализующая subscript для работы с квадратной матрицей:
struct Matrix { let size: Int private var grid: [Int] init(size: Int) { self.size = size self.grid = Array(repeating: 0, count: size * size) } subscript(row: Int, column: Int) -> Int { get { precondition(indexIsValid(row, column), "Index out of range") return grid[(row * size) + column] } set { precondition(indexIsValid(row, column), "Index out of range") grid[(row * size) + column] = newValue } } private func indexIsValid(_ row: Int, _ column: Int) -> Bool { return row >= 0 && row < size && column >= 0 && column < size } } var m = Matrix(size: 3) m[1,2] = 7 print(m[1,2]) // 7
Ключевые особенности:
Subscript могут использоваться только для коллекций?
Нет, subscript могут быть реализованы для любых типов: структура, класс, enum. Тип данных внутри не должен быть именно коллекцией, главное — логика обработки запросов через subscript.
Можно ли сделать несколько subscript с разной сигнатурой в одном типе?
Да, разрешено перегружать subscript с разной сигнатурой параметров:
struct Example { subscript(index: Int) -> Int { return index } subscript(key: String) -> String { return key.uppercased() } }
Допускается ли использовать subscript как computed property без set?
Да, subscript может быть только для чтения (get-only), тогда попытка записи вызовет ошибку компиляции.
struct ReadOnly { subscript(index: Int) -> Int { index * index } }
В большой структуре реализован subscript без проверки диапазона, что приводит к краху приложения при некорректном индексе.
Плюсы:
Минусы:
Matrix реализован с precondition на диапазон индексов. Любая ошибка отлавливается сразу, не попадает в production.
Плюсы:
Минусы: