История вопроса:
Subscript был введён в Swift для удобной и безопасной работы с коллекциями и структурами данных, позволяя обращаться к элементам с помощью знакомого синтаксиса квадратных скобок.
Проблема:
Путаница между subscript, методами и computed свойствами, их областью применения, а также ошибочное использование subscript для доступа к данным, которые не являются коллекциями или имеют побочный эффект.
Решение:
Subscript — специальный механизм, позволяющий предоставить доступ к элементам объекта с помощью квадратных скобок. Он может быть read-only или read-write и поддерживает параметры любой природы: не только Int, но и String или свои типы.
Пример кода:
struct Matrix { private var data: [[Int]] init(rows: Int, columns: Int) { data = Array(repeating: Array(repeating: 0, count: columns), count: rows) } subscript(row: Int, column: Int) -> Int { get { data[row][column] } set { data[row][column] = newValue } } } var matrix = Matrix(rows: 2, columns: 2) matrix[0, 1] = 5 print(matrix[0, 1]) // 5
Ключевые особенности:
Может ли subscript иметь более одного параметра?
Да, subscript может принимать любой набор параметров и любого типа (например, tuple).
Пример кода:
// См. пример выше с Matrix, где subscript(row: Int, column: Int)
Можно ли реализовать subscript только для чтения (read-only)?
Да, если не объявлять set, subscript будет только для чтения.
Пример кода:
struct ReadOnlyArray { private let items = [1, 2, 3] subscript(index: Int) -> Int { return items[index] } }
В чём разница между subscript и computed property?
Computed property всегда имеет фиксированное имя и не принимает параметров. Subscript позволяет обращаться по переменному индексу, имитируя коллекционную структуру.
В custom-структуре subscript используется для изменения глобального состояния, что вызывает неожиданные сайд-эффекты при простом обращении к элементу в массиве.
Плюсы:
Минусы:
Используется subscript только для работы с приватным массивом внутри структуры, реализована обработка выхода за границы с возвратом nil.
Плюсы:
Минусы: