ПрограммированиеiOS разработчик

Объясните особенности работы с Subscripts в Swift. Какие ограничения существуют для subscript, как можно расширить этот механизм и где его стоит применять? Приведите пример нестандартного subscript.

Проходите собеседования с ИИ помощником Hintsage

Ответ

Subscripts в Swift позволяют предоставлять доступ к значениям типа по ключу или индексу схожим образом с массивами или словарями, но для любых своих собственных типов. Синтаксис похож на функцию, но доступ осуществляется в скобках: object[key].

Особенности:

  • Класс или структура могут иметь несколько subscript (оверлоадинг по параметрам).
  • Subscript может быть read-only или read-write (содержать только get, либо get и set).
  • Subscript может иметь любое число параметров и типов (например, два индекса).
  • Нет поддержки variadic параметров.

Применение:

  • Для упрощённого доступа к коллекциям, матрицам, custom-объектам, сериализуемым значениям и т.д.

Пример: Двумерный массив (матрица) и subscript с двумя параметрами:

struct Matrix { let rows: Int, columns: Int private var grid: [Double] init(rows: Int, columns: Int) { self.rows = rows self.columns = columns grid = Array(repeating: 0.0, count: rows * columns) } subscript(row: Int, column: Int) -> Double { get { precondition(isValid(row: row, column: column), "Index out of range") return grid[(row * columns) + column] } set { precondition(isValid(row: row, column: column), "Index out of range") grid[(row * columns) + column] = newValue } } private func isValid(row: Int, column: Int) -> Bool { return row >= 0 && row < rows && column >= 0 && column < columns } } var matrix = Matrix(rows: 2, columns: 2) matrix[0,1] = 5.0 print(matrix[0,1]) // 5.0

Вопрос с подвохом

Может ли subscript иметь параметр типа inout или быть mutating в структуре?

Ответ:

  • Параметр subscript не может быть inout.
  • Subscript в value type (struct/enum) может быть объявлен как mutating set, что позволяет изменять self внутри set:
struct Counter { var value: Int = 0 subscript(increment: Bool) -> Int { mutating get { value += increment ? 1 : -1 return value } } }

Примеры реальных ошибок из-за незнания тонкостей темы


История

В кастомной коллекции забыли сделать set в subscript mutating в структуре, в результате любая попытка изменять элемент через subscript вызывала ошибку компиляции. Ошибка проявилась на этапе интеграции коллекции после долгой отладки.


История

В кастомном subscript не реализовали корректную обработку выхода за границы индекса, что вызвало краши при обращении за пределы диапазона. В результате падали бизнес-критичные функции обработки данных.


История

Реализовали subscript с двумя параметрами у enum для кеширования, но не учли, что subscript не может быть static (у типа), а только у экземпляра. Архитектурное решение оказалось ошибочным, пришлось переписывать API взаимодействия коллекции.