Данные и управление

Коллекции и включения

Как выбрать Array, Map или Set и преобразовать данные каноническим включением.

Коллекцию выбирают по поведению, которое должна сохранять программа: важны ли порядок и повторы, нужен ли поиск по ключу или достаточно уникальности. Включение коллекции — компактная запись фильтрации и преобразования, которая не меняет правила порядка выбранной коллекции.

Сначала выберите коллекцию

КоллекцияКогда выбиратьНаблюдаемое поведение
Array<T>Нужны порядок, доступ по позиции и повторяющиеся значенияОбход по возрастанию индекса, повторы сохраняются
Map<K, V>Значение выбирается по ключуКлючи хранят порядок вставки; обновление существующего ключа сохраняет его место
Set<T>Важна уникальность значенийПервый из равных элементов сохраняет своё место

Запустите пример

Сохраните код в файле collections-comprehensions.tpz:

TOPAZ
let scores = [10, 25, 10]
let labels = map { "Ada": 10, "Lin": 25 }
let unique = set { 10, 25, 10 }
let focused = [ for score in scores if score >= 20 => score * 2 ]

let first = scores[0]
let missing = scores.get(9)
let hasAda = "Ada" in labels.keys
let missingLabel = match missing {
    case Some(value) => "found {value}"
    case None => "missing"
}

print("{scores}:{unique.toArray()}:{labels.keys}")
print("{focused}:{first}:{hasAda}")
print(missingLabel)
BASH
topaz check collections-comprehensions.tpz
topaz run collections-comprehensions.tpz

Программа напечатает:

Вывод
[10, 25, 10]:[10, 25]:[Ada, Lin]
[50]:10:true
missing

Массив сохраняет оба значения 10. Множество объединяет повтор и оставляет место первого 10. labels.keys возвращает массив ключей в порядке вставки, поэтому проверка принадлежности записана как "Ada" in labels.keys.

Выбирайте чтение и изменение осознанно

scores[0] читает элемент непосредственно по индексу. Отрицательный или выходящий за границы индекс останавливает программу с ошибкой выполнения. scores.get(9) — безопасное чтение: оно возвращает Option, который пример разбирает с помощью match.

Для изменения коллекции на месте корневое связывание должно быть изменяемым. Перед операцией вроде values.push(...) объявите let mut values = [...]. Неизменяемое связывание всё равно можно использовать в выражении, которое создаёт новую коллекцию.

Повтор ключа в Map обрабатывается не так, как повтор элемента в Set. Повтор простого литерального ключа — статическая ошибка. Если равенство ключей выясняется только во время выполнения, сначала вычисляются операнды, затем создание завершается ошибкой без перезаписи. Для намеренного добавления или обновления ключа используйте Map.insert.

Литерал, цикл или включение?

  • Если элементы перечислены прямо в коде, используйте [a, b], set { a, b } или map { key: value }.
  • Если тело удобнее читать как последовательность шагов, используйте for item in source { ... }. В позиции инструкции он выполняет действия, а в позиции выражения собирает результаты тела в Array.
  • Если фильтр и преобразование образуют одно ясное выражение, используйте [ for item in source if condition => result ]. Для уникальных результатов замените внешние скобки на set { ... }, а для пар ключ–значение — на map { ... }.

Список условий включения начинается с for, продолжается операторами for или if без запятых и завершается =>. Условия вкладываются слева направо. Итоговая коллекция становится доступна только после успешного выполнения всех достигнутых условий и тел.

Частые ошибки

Типы коллекций записываются как Array<T>, Map<K, V> и Set<T>; форма [T] типом коллекции не является. Литералам множества и отображения нужны слова set и map: #{...} и голая форма {key: value} не обозначают эти коллекции.

Форма key in map недопустима — используйте key in map.keys. Несовпадение допускающего отказ шаблона во включении вызывает ошибку, а не автоматически отбрасывает элемент. Для пропуска элементов добавьте явное условие if.

Точные границы

  • Раскрытие внутри массива принимает только другой Array. Для литералов и включений Set и Map раскрытия нет.
  • Пустым set {} и map {} нужен ожидаемый тип Set<T> или Map<K, V>.
  • Ключи отображения и элементы множества должны рекурсивно допускать использование в качестве ключа.
  • Удаление освобождает место в порядке; повторная вставка добавляет новое место в конец. Обновление значения существующего ключа его место не меняет.
  • for обходит Array, целочисленные диапазоны, Set и map.keys. Для строки нужно явно получить последовательность скаляров.

Пользовательские итераторы, генераторы, ленивые и параллельные включения, раскрытие произвольных итерируемых значений и коллекции без определённого порядка в текущий язык не входят.

Начните с урока Данные и управление. Связывания во включениях разобраны в разделе Шаблоны и управление потоком, а точные повседневные методы — в разделе Операции с коллекциями.