Индексы
Доступ к элементам коллекции.
Классы, структуры и перечисления могут определять индексы, которые являются сокращениями для доступа к элементам члена коллекции, списка или последовательности. Вы используете индексы для установки и получения значений по индексу без необходимости в отдельных методах для установки и получения. Например, вы получаете доступ к элементам в экземпляре Array как someArray[index] и элементам в экземпляре Dictionary как someDictionary[key].
Вы можете определить несколько индексов для одного типа, и соответствующая перегрузка индекса будет выбрана в зависимости от типа значения индекса, которое вы передаёте индексу. Индексы не ограничены одной размерностью, и вы можете определить индексы с несколькими входными параметрами, чтобы удовлетворить потребностям вашего пользовательского типа.
Синтаксис индексов
Индексы позволяют вам запросить экземпляры типа, написав одно или несколько значений в квадратных скобках после имени экземпляра. Их синтаксис аналогичен синтаксису метода экземпляра и синтаксису вычисляемого свойства. Вы пишете определения индексов с ключевым словом subscript, и указываете один или несколько входных параметров и тип возвращаемого значения, так же как и методы экземпляров. В отличие от методов экземпляров, индексы могут быть читаемыми, записываемыми или только для чтения. Это поведение передаётся с помощью геттера и сеттера так же, как и для вычисляемых свойств:
subscript(index: Int) -> Int {
get {
// Return an appropriate subscript value here.
}
set(newValue) {
// Perform a suitable setting action here.
}
} Тип newValue совпадает с возвращаемым значением индекса. Как и для вычисляемых свойств, вы можете не указывать параметр сеттера (newValue). По умолчанию для вашего сеттера предоставляется параметр, называемый newValue, если вы его не укажете.
Как и для вычисляемых свойств только для чтения, вы можете упростить объявление индекса только для чтения, удалив ключевое слово get и его фигурные скобки:
subscript(index: Int) -> Int {
// Return an appropriate subscript value here.
} Вот пример реализации индекса только для чтения, который определяет структуру TimesTable для представления таблицы умножения n-го порядка целых чисел:
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
print("six times three is \(threeTimesTable[6])")
// Prints "six times three is 18" В этом примере создаётся новый экземпляр TimesTable для представления таблицы умножения на три. Это указывается путём передачи значения 3 методу initializer структуры в качестве значения для параметра multiplier экземпляра.
Вы можете запросить экземпляр threeTimesTable, вызвав его индекс, как показано в вызове threeTimesTable[6]. Это запрашивает шестой элемент в таблице умножения на три, который возвращает значение 18, или 3 раз 6.
Примечание: Таблица умножения n-го порядка основана на фиксированном математическом правиле. Некорректно устанавливать
threeTimesTable[someIndex]в новое значение, поэтому индекс дляTimesTableопределён как индекс только для чтения.
Использование индексов
Точное значение «индекс» зависит от контекста его использования. Индексы обычно используются как сокращение для доступа к элементам члена коллекции, списка или последовательности. Вы можете реализовать индексы наиболее подходящим образом для функциональности вашего конкретного класса или структуры.
Например, тип Dictionary Swift реализует индекс для установки и получения значений, хранящихся в экземпляре Dictionary. Вы можете установить значение в словаре, предоставив ключ типа ключа словаря в квадратных скобках индекса и присвоив значение типа значения словаря индексу:
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] numberOfLegs["bird"] = 2
В примере выше определяется переменная, называемая numberOfLegs, и инициализируется она словарем, содержащим три пары «ключ-значение». Тип словаря numberOfLegs определяется как [String: Int]. После создания словаря в этом примере используется присваивание по индексу, чтобы добавить ключ String со значением "bird" и значение Int со значением 2 в словарь.
Дополнительную информацию об индексировании по Dictionary см. в <doc:CollectionTypes#Accessing-and-Modifying-a-Dictionary>.
Примечание: тип
DictionarySwift реализует индексирование по «ключ-значение» как индекс, который принимает и возвращает необязательный тип. Для словаряnumberOfLegsвыше индекс «ключ-значение» принимает и возвращает значение типаInt?или «необязательный int». ТипDictionaryиспользует необязательный тип индекса для моделирования того факта, что не каждый ключ имеет значение, и для удаления значения по ключу, присвоив значениеnilэтому ключу.
Варианты индексов
Индексы могут принимать любое количество входных параметров, и эти входные параметры могут быть любого типа. Индексы также могут возвращать значение любого типа.
Как и функции, индексы могут принимать переменное количество параметров и предоставлять значения по умолчанию для своих параметров, как описано в <doc:Functions#Variadic-Parameters> и <doc:Functions#Default-Parameter-Values>. Однако, в отличие от функций, индексы не могут использовать параметры «ввод-вывод».
Класс или структура могут предоставлять любое количество реализаций индекса, и соответствующий индекс будет определяться на основе типов значения или значений, содержащихся в скобках индекса в момент использования индекса. Это определение нескольких индексов известно как перегрузка индексов.
Хотя наиболее распространённым случаем является индекс с одним параметром, вы также можете определить индекс с несколькими параметрами, если это подходит для вашего типа. В следующем примере определяется структура Matrix, которая представляет собой двумерную матрицу значений Double. Индекс структуры Matrix принимает два целочисленных параметра:
struct Matrix {
let rows: Int, columns: Int
var grid: [Double]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(repeating: 0.0, count: rows * columns)
}
func indexIsValid(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
subscript(row: Int, column: Int) -> Double {
get {
assert(indexIsValid(row: row, column: column), "Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValid(row: row, column: column), "Index out of range")
grid[(row * columns) + column] = newValue
}
}
} Matrix предоставляет инициализатор, который принимает два параметра, называемых rows и columns, и создаёт массив, достаточно большой для хранения значений rows * columns типа Double. Каждой позиции в матрице задаётся начальное значение 0.0. Для достижения этого размер массива и начальное значение ячейки 0.0 передаются в инициализатор массива, который создаёт и инициализирует новый массив правильного размера. Этот инициализатор более подробно описан в <doc:CollectionTypes#Creating-an-Array-with-a-Default-Value>.
Вы можете создать новый экземпляр Matrix, передав подходящее количество строк и столбцов в его инициализатор:
var matrix = Matrix(rows: 2, columns: 2)
В примере выше создаётся новый экземпляр Matrix с двумя строками и двумя столбцами. Массив grid для этого экземпляра Matrix фактически является уплощённой версией матрицы, прочитанной сверху слева донизу справа:
Значения в матрице можно установить, передав значения строки и столбца в индекс, разделённые запятой:
matrix[0, 1] = 1.5 matrix[1, 0] = 3.2
Эти два оператора вызывают сеттер индекса для установки значения 1.5 в верхнюю правую позицию матрицы (где row равно 0, а column равно 1), и 3.2 в нижнюю левую позицию (где row равно 1, а column равно 0):
Геттер и сеттер индекса Matrix содержат утверждение для проверки того, что значения row и column индекса являются допустимыми. Для помощи в этих утверждениях Matrix включает вспомогательный метод под названием indexIsValid(row:column:), который проверяет, находятся ли запрошенные row и column внутри границ матрицы:
func indexIsValid(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
} Возникает утверждение, если вы пытаетесь получить доступ к индексу, выходящему за пределы границ матрицы:
let someValue = matrix[2, 2] // This triggers an assert, because [2, 2] is outside of the matrix bounds.
Индексы типа
Индексы экземпляра, как описано выше, — это индексы, которые вы вызываете для экземпляра определённого типа. Вы также можете определить индексы, которые вызываются для самого типа. Этот вид индекса называется индексом типа. Вы указываете индекс типа, написав ключевое слово static перед ключевым словом subscript. Классы могут использовать ключевое слово class вместо этого, чтобы разрешить подклассам переопределять реализацию этого индекса суперклассом. Приведённый ниже пример демонстрирует, как определить и вызвать индекс типа:
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
static subscript(n: Int) -> Planet {
return Planet(rawValue: n)!
}
}
let mars = Planet[4]
print(mars)
This source file is part of the Swift.org open source project
Copyright © 2014 - 2025 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception