Кортежи (Tuple)
В Swift кортежи используются для создания упорядоченных списков значений.
Что такое кортеж?
Кортеж (tuple) представляет собой упорядоченный, разделенный запятыми список значений, который обрамляется круглыми скобками. И каждое значение внутри кортежа может относиться к разным типам данных.
Синтаксис кортежа
В общей форме кортеж записывается так:
var tupleName: (DataType, ...) = (value1, ...)
Здесь:
(DataType, ...)
- тип данных кортежа: в круглых скобках указаны типы данных элементов;(value1, ...)
- значения элементов кортежа: в круглых скобках указаны значения элементов.
В короткой форме записи тип данных (DataType, ...)
можно не указывать. Тип данных будет определен исходя из контекста значения введенных элементов.
Пример:
var tupleName = (value1, ...)
Пример кортежа:
let flight = ("LAX", 747)
В приведённом выше примере создаётся константа flight
, которая инициализирована со значением в виде кортежа ("LAX", 747)
. В кортеже можно увидеть два значения, которые разделены запятой и которые заключены в круглые скобки.
Тип данного кортежа (String, Int)
- определён из типа данных его элементов.
Так как кортеж - это упорядоченный список, то порядок элементов имеет значение. Кортеж по типу (Int, String)
и кортеж по типу (String, Int)
- это два разных кортежа по типу данных.
Приведенные ниже кортеж имеют разные типы:
("LAX", 747) // (String, Int)
(747, "LAX") // (Int, String)
Несмотря на то, что оба кортежа содержат одинаковые значения с одинаковым типом, их типы различны, поскольку порядок значений различен.
Не следует путать кортежи с массивами, словарями или множествами. Кортежи не являются коллекциями, однако, они так же объединяют значения.
Значения кортежа могут иметь разные типы и можно изменять их значения при условии, что они объявлены как изменяемые с помощью переменной var
.
После инициализации кортежа его тип данных фиксируется. А это значит, что нельзя добавлять в него новые элементы. Порядок элементов кортежа также не может измениться.
Операции с кортежами
Предположим, необходимо хранить информацию о названии и цене некоторого продукта. Можно создать кортеж с одним значением для хранения имени (String) и другим значением - для хранения цены (Float).
Создание кортежа
В Swift используются круглые скобки ()
для хранения элементов кортежа.
Например:
var product = ("MacBook", 1099.99)
Здесь product
— это кортеж со строковым значением "Macbook"
и целым числом 1099,99
.
Получение значений элементов кортежа
Как и в массиве, каждый элемент кортежа имеет индекс, который представлен порядковыми номерами (0, 1, …), где первый элемент имеет индекс 0
.
Для доступа к элементам кортежа используется номер индекса.
В отличие от массивов, где доступ по индексу осуществляется с помощью квадратных скобок ([]
), в кортежах используется конструкция “обозначение через точку” (dot-notations) - как при получении доступа к элементам классов, структур: пишется имя кортежа, потом ставится точка .
и за ней - необходимый индекс.
Например:
// access the first element
product.0
// access second element
product.1
Пример кортежа:
// create tuple with two elements
var product = ("MacBook", 1099.99)
// access tuple elements
print("Name:", product.0)
print("Price:", product.1)
// Output
// Name: MacBook
// Price: 1099.99
В приведенном выше примере был создан кортеж с именем product
с двумя значениями: "MacBook"
и 1099.99
. Здесь использовался номер индекса: product.0
и product.1
для доступа к элементам кортежа.
Примечание. Поскольку первое значение кортежа — это строка, а второе — целое число, то тип кортежа —
(String, Int)
.
Попытка доступа к элементу по несуществующему индексу приведёт к ошибке.
Например:
var company = ("Programiz", "Apple")
company.2 // Error: Value of tuple type '(String, String)' has no member '2'
Нельзя получить доступ к несуществующему элементу. В этом случае ошибка сообщает, что в кортеже нет элемента с запрошенным индексом.
Изменение элемента кортежа
Можно изменить элемент кортежа, присвоив новое значение по конкретному индексу.
Например:
// create tuple with two elements
var product = ("MacBook", 1099.99)
print("Original Tuple: ")
// access tuple elements
print("Name:", product.0)
print("Price:", product.1)
// Output
// Original Tuple:
// Name: MacBook
// Price: 1099.99
// modify second value
product.1 = 1299.99
print("\nTuple After Modification: ")
// access tuple elements
print("Name:", product.0)
print("Price:", product.1)
// Output
// Tuple After Modification:
// Name: MacBook
// Price: 1299.99
В приведенном выше примере был создан кортеж с именем product
со значениями: MacBook
и 1099,99
. Обратите внимание на строку:
product.1 = 1299.99
Здесь было изменено значение кортежа с индексом 1
: с 1099.99
на 1299,99
.
Примечание. Индекс кортежа всегда начинается с 0. Следовательно, первый элемент кортежа имеет индекс 0, а не 1.
Добавление/удаление элементов из кортежа
Нельзя добавлять или удалять элементы из кортежа в Swift.
Нельзя добавить элемент по методу, как в словаре.
Пример:
var company = ("Programiz", "Apple")
company.2 = "Google" // Error: Value of tuple type '(String, String)' has no member '2'
Нельзя удалить элемент, метода remove()
нет для кортежа.
Пример:
var company = ("Programiz", "Apple")
company.remove("Apple") // Error: Value of tuple type '(String, String)' has no member 'remove'
Здесь создали кортеж со значениями: "Programiz"
и "Apple"
. Теперь тип кортежа фиксируется на (String, String)
. Итак, когда пытаемся добавить и удалить элементы из кортежа, то получаем ошибки.
Сравнение кортежей
Можно сравнивать кортежи друг с другом, если их типы одинаковы и если сами типы соответствуют протоколу Equatable
. Другими словами, если можно сравнить значения, то можно сравнить и сами кортежи:
let a = ("AMS", 737)
let b = ("LAX", 737)
print(a == b)
// Output
// false
print(a < b)
// Output
// true
let c = ("AMS", "A330-800")
c == b // Error: Cannot convert value of type '(String, Int)' to expected argument type '(String, String)'
В этом примере, в конце получается ошибка компиляции, посколько типы сравниваемых кортежей не совпадают.
Именованные кортежи
В Swift также можно указать имена для каждого элемента кортежа.
Например:
var company = (product: "Programiz App", version: 2.1)
Чтобы получить доступ к элементам именованного кортежа, также можно использовать эти имена вместо номеров индексов:
// access "Programiz App"
company.product
Доступ по имени элемента осуществляется так же, как и по индексу: используя точку (.
) после имени кортежа.
Пример именованного кортежа:
// create named tuple
var company = (product: "Programiz App", version: 2.1)
// access tuple element using name
print("Product:", company.product)
print("Version:", company.version)
// Output
// Product: Programiz App
// Version: 2.1
В приведенном выше примере были предоставлены имена: product
и version
для первого и второго элемента кортежа. Использовалось “обозначение через точку” (dot-notations) для доступа к элементам и подставлялись имена для доступа к соответствующим значениям кортежа.
Примечание. Лучше всего использовать именованные кортежи, так как это делает код более читабельным.
Вложенный кортеж
В Swift можно создать кортеж, как элемент другого кортежа.
Например:
var alphabets = ("A", "B", "C", ("a", "b", "c"))
Здесь есть кортеж ("a", "b", "c")
в качестве третьего элемента кортежа alphabets
. Это называется вложенным кортежем.
Пример вложенного кортежа:
var alphabets = ("A", "B", "C", ("a", "b", "c"))
// access first element
print(alphabets.0)
// Output
// prints "A"
// access the third element
print(alphabets.3)
// Output
// ("a", "b", "c")
// access nested tuple
print(alphabets.3.0)
// Output
// prints "a"
В приведенном выше примере обратите внимание на строку:
print(alphabets.3)
// Output
// ("a", "b", "c")
Здесь получили доступ к третьему элементу кортежа alphabets
. Поскольку третий элемент также является кортежем, использовалось “обозначение через точку” (dot-notations):
alphabets.3.0
для доступа к первому элементу вложенного кортежа.
Передача значений кортежа в переменные или константы
Для этого можно разложить кортеж на отдельные элементы и присвоить их соответствующим константам или переменным.
Пример:
let (airport, _, heading) = ("LAX", 747, 270)
print(airport)
// Output
// LAX
Вот что происходит в приведенном выше коде:
- Есть кортеж
("LAX", 747, 270)
. Он не присваивается отдельной переменной или константе, но вместо этого, его значения раскладываются на отдельные элементы и присваиваются отдельным константам; - Назначем константе
airport
значение"LAX"
; - Подчеркивание
_
- это значение, которое игнорируется.
Еще пример. Предположим, что используем функцию, которая возвращает нам код состояния HTTP. Такой код обычно состоит из числа, например “404”, и некоторого текста.
Пример:
func getStatusCode() -> (Int, String) {
return (404, "Not Found")
}
let (code, text) = getStatusCode()
print("Возвращено значение \(code) и текст: '\(text)'")
// Output
// Возвращено значение 404 и текст: 'Not Found'
Функция getStatusCode()
возвращает кортеж типа (Int, String)
, который содержит два значения.
Если необходимо получить доступ к отдельным значениям, то раскладываем кортеж с помощью (code, text)
. Далее, можно использовать отдельные константы code
и text
, чтобы вывести на консоль нужные значения.
Больше про переменные можно узнать в отдельной статье. См. ссылку внизу.
Словарь и массив внутри кортежа
В Swift можно использовать словарь для добавления элемента в кортеж.
Например:
var laptopLaunch = ("MacBook", 1299, ["Nepal": "10 PM", "England": "10 AM"])
print(type(of: laptopLaunch))
// Output
// (String, Int, Dictionary<String, String>)
print(laptopLaunch.2)
// Output
// ["Nepal": "10 PM", "England": "10 AM"]
laptopLaunch.2["USA"] = "11 AM"
print(laptopLaunch.2)
// Output
// ["Nepal": "10 PM", "England": "10 AM", "USA": "11 AM"]
В приведенном выше примере, третий элемент кортежа — это словарь:
["Nepal": "10 PM", "England": "10 AM"]
Можно добавлять элементы в словарь. Для этого необходимо получить доступ к словарю и добавить элемент стандартным способом. Для этого использовался следующий код, чтобы добавить элемент в словарь:
laptopLaunch.2["USA"] = "11 AM"
Таким образом, можно добавить элемент в кортеж. И тип кортежа остается прежним (String, String, Dictionary)
. Таким образом, не получаем никаких ошибок.
Таким же способом можно использовать массив.
Например:
var laptopLaunch = ("MacBook", 1299, ["10 PM", "10 AM"])
print(type(of: laptopLaunch))
// Output
// (String, Int, Array<String>)
print(laptopLaunch.2)
// Output
// ["10 PM", "10 AM"]
laptopLaunch.2.append("11 AM")
print(laptopLaunch.2)
// Output
// ["10 PM", "10 AM", "11 AM"]
Больше про массивы и словари можно узнать в отдельной статье. См. ссылку внизу.
Кортежи в программировании на Swift
Кортежи весьма полезны в разработке для iOS. На данном этапе были рассмотрены несколько типичных вариантов использования кортежей. Что еще можно с ними сделать?
Можно рассматривать кортежи как крошечные классы, которые можно использовать без создания самого класса.
Например, есть такой класс Flight
:
class Flight {
var airport:String
var airplane:Int
}
let flight = Flight(airport: "AMS", airplane: 330)
print("Мы летим в \(flight.airport)...")
Приведенный выше код сначала определяет класс Flight
, а затем инициализирует экземпляр данного класса flight
. Можно сделать то же самое с кортежем, с гораздо меньшим количеством кода:
let flight = (airport: "AMS", airplane: 330)
print("Мы летим в \(flight.airport)...")
Также можно использовать псевдоним типа (Typealias):
typealias Flight = (airport: String, airplane: Int)
let flight: Flight = ("HND", 737)
print("Мы летим в \(flight.airport)..."
Здесь создаётся новый псевдоним типа Flight
для типа данных кортежа (airport: String, airplane: Int)
. Далее, можно использовать тип данных Flight
вместо типа данных кортежа (airport: String, airplane: Int)
. Константа flight
будет с типом данных кортежа, что позволит получать доступ к элементам по индексу или именам элементов.
Кортежи можно использовать для доступа к индексам и значениям элементов массива с помощью функции enumerated()
:
let drivers = ["Magnussen", "Raikkonen", "Hamilton", "Verstappen"]
for (index, name) in drivers.enumerated() {
print("\(name) индекс: \(index)")
}
// Output
// Magnussen индекс: 0
// Raikkonen индекс: 1
// Hamilton индекс: 2
// Verstappen индекс: 3
В этом примере, в цикле с помощью функции enumerated()
была получена пара индекс-значение
в виде кортежа в каждой итерации цикла. В качестве примера, здесь выводилась в консоль строка текста, которая содержала индекс и значение каждого элемента кортежа.
Еще полезные ссылки
Также информацию по кортежам можно получить на странице официальной документации.
Ссылки на официальную документацию: