0:00
Привет.
В этой лекции мы рассмотрим протокол collection, индексы и то,
как создать свою коллекцию.
Коллекция swift — это стабильная последовательность элементов,
которую можно безопасно интегрировать много раз.
В отличие от sequence, они не могут быть бесконечными.
Протокол collection наследуется от sequence, добавляя индексы,
сабскрипты и обязательство не разрушать данные при проходе итератора.
Благодаря последнему можно использовать этот протокол,
чтобы показать, что ваша последовательность стабильная,
даже если вам не нужна остальная функциональность коллекции.
При создании собственной коллекции обязательными для имплементации являются
свойства start index, and index, методы subscript position и индекс after.
Для остальных уже есть реализация по умолчанию.
К сожалению, нет никакого механизма, позволяющего это понять.
Приходится играть в угадайку с компелятором либо искать ответы в
документации к протоколу.
Рассмотрим простейшую коллекцию Stack.
Мы объявляем структуру с одной приватной переменной, private srotage,
которая имеет тип массива строк, а также два метода, изменяющих данную коллекцию
— push, который добавляет элемент в конец данного массива, и pop,
который возвращает последний элемент массива, если он есть, и удаляет его.
Рассмотрим пример использования данного стэка.
Создаем переменную с пустым стэком.
Добавляем в него строки "Hello", "World" и вопросительный знак.
Делаем pop на последнем из элементов.
Как видим, это вопросительный знак.
И добавляем в стэк восклицательный знак.
Если же сейчас мы начнем получать все элементы данного стэка,
то мы получим восклицательный знак, World, Hello.
Удостоверимся в этом.
Как видите, все работает как и ожидалось.
[БЕЗ_ЗВУКА] Добавим
нашему стэку поддержку протокола collection через расширение.
Для этого реализуем минимально необходимый набор для поддержки протокола.
Associated type явно указывать необязательно,
iii сам поймет что evenent в нашем случае это строка, а index — это интеджер.
Объявляем extension над типом стэк.
Указываем, что этим экстеншеном мы добавляем поддержку протокола collection.
Для этого нам необходимо объявить переменный старт индекс (в нашем
случае это всегда будет 0), end indes,
который указывате на элемент следующий за последним.
То есть в нашем случае это количество элементов в массиве.
Также необходим метод index auto,
который позволяет из индекса получить следующий за ним.
В нашем случае это просто прибавление единиц,
а также элемент по определенному индексу.
Обращаемся к нашему приватному storage по данному индексу.
Помимо element и index, в протоколе имеются и другие associated type.
Например, iterator, который наследуется от sequence.
В нашем случае он будет иметь тип index in iterator aztek.
Это просто итератор,
который оборачивает коллекцию и использует ее для получения следующего элемента.
Subsequence, также полученное от sequence,
будет иметь тип slice с дженерик-параметром stack.
Имеет смысл заменить его на тип самой коллекции.
Чуть позже я покажу, как это сделать.
Индекс distance по умолчанию имеет тип integer и используется для указания
разницы между двумя индексами.
Его менять не нужно, а indexes в нашем случае будут иметь тип default indexes
с дженерик-параметром int, являются еще одним репером над коллекцией,
содержат все валидные индексы данной коллекции.
Поддержав этот протокол, мы получаем бесплатно кучу полезных методов.
Можно использовать коллекцию в цикле for in.
Продемонстрируем это.
Делаем цикл по всем элементам нашего стэка и печатаем каждый из них.
Как видите, мы получаем Hello, World, восклицательный знак.
Также мы можем получить количество элементов в нашем стэке, проверить,
является ли он пустым, а также составить массив из части элементов нашего стэка.
Также мы можем добавить поддержку протокола expressable iii literal.
Это позволит инициализировать стэк с помощью литералов массива.
Все что необходимо сделать — это добавить еще один конструктор.
Он получает на вход список строк.
Все, что мы делаем внутри — это присваиваем этот массив к
нашему приватному storage.
Далее мы можем объявлять константу нашего стэка, присваивая ей массив.
Еще одним важным понятием, которое мы сегодня рассмотрим, являются индексы.
В предыдущих примерах в качестве индекса мы для удобства использовали int,
но коллекция может иметь индекс любого сравнивого типа.
Именно поэтому не стоит использовать индекс вручную или пытаться
найти следующий, прибавив единицу.
Одним из примеров является строка.
Ее индексами являются структура string index.
Для работы нужно использовать специальные методы коллекции.
Рассмотрим некоторые из них.
Объявляем константу со строкой и получаем индекс элемента строчной s.
Присваиваем этот индекс какой-то другой переменной.
Длаее мы можем найти индекс, следующий за данным индексом,
и присовить его той же переменной.
Заметьте, что индексы имеют тип string index, а не integer,
что могло бы показаться логичным.
Следующий индекс можно искать и без переприсвоения.
Мы просто изменяем уже существующую переменную.
Index distance показывает расстояние между двумя индексами.
Найдем расстояние между двумя переменными с индексами, которые у нас есть.
В случае со строкой, индекс distance является интеджером.
И в нашем случае он равен 2.
Мы также можем добавить некий индекс distance к любому индексу.
Добавим полученное расстояние к одному из существующих индексов.
Теперь мы можем удостовериться, что эти индексы равны.
В коллекции есть также два специальных индекса.
Start index и end index.
Они указывают на первый элемент коллекции и на следующий за последним.
То есть end index не указывает на валидный элемент коллекции.
Это позволяет писать циклы с условями while index меньше, чем end index.
До версии Swift 3.0 индексы могли сами вычислить следующий индекс,
но зачастую это требовало хранения в индексе ссылки на коллекцию.
Это привело к тому, что изменение коллекции при проходе в цикле создавало
ненужные копии, и оптимизация копирования уже не действовала.
Также одним важным изменением, связанным с коллекцией, является то,
что с версией 4.0 строки снова стали коллекциями.
Возможно, вам встретится код, написанный на Swift 3, где для того, чтобы пройтись
по всем элементам строки необходимо было использовать свойство characters.
Помимо collection, в Swift есть и другие протоколы для коллекций.
By directional collection добавляет в коллекцию возможность получить
предыдущий индекс.
А random access collection не добавляет новых методов,
но гарантирует доступ к любому индексу за константное время.
Mutable collection добавляет возможность изменять содержимое коллекции через
сабскрипты.
Range replacable collection позволяет заменить сразу диапозон индексов.
Требования к производительности различаются в этих протоколах.
Например, свойство count в random access collection имеет константную сложность,
но для других это может быть и сложность O большое от n.
Всегда проверяйте описание конкретной реализации коллекции, и комментируйте
особенности своей, если она не укладывается в стандартные требования.
В этой лекции мы рассмотрели протокол collection, научились работать с
индексами, и написали свой простой стэк, который поддерживает протокол collection.