OxL Справочник OxL
РусскийEnglish

Шаг 6. Коллекции и итераторы

Зачем#

Три коллекции покрывают подавляющее большинство задач: List<T> (упорядоченный список), Map<K, V> (словарь) и Set<T> (множество уникальных значений). Map и Set итерируются в порядке вставки, поэтому вывод детерминирован — это важно для тестов и воспроизводимых журналов.

Обработка коллекций — это конвейеры «отфильтровать → преобразовать → собрать». Они ленивы: iter<T> ничего не вычисляет, пока вы не попросите результат (toList, fold, for). Поэтому длинный конвейер не создаёт промежуточных списков.

Список, словарь, множество#

oxl✓ проверяется в CI
fn main() io {
  var xs: List<i32> = [5, 3, 8]
  xs.push(1)
  xs.sort()
  print("{xs} first={xs.first() ?? -1} last={xs.last() ?? -1}")
  print("{xs.map(x => x * 10)} {xs.filter(x => x > 3)} sum={xs.fold(0, (a, x) => a + x)}")
  print("{xs.contains(8)} {xs.any(x => x > 7)} {xs.all(x => x > 1)} {xs.count(x => x % 2 == 1)}")

  var stock: Map<str, i32> = {"apple": 3, "pear": 0}  // Map<K, V>: литерал {k: v}
  stock["plum"] = 7  // присваивание по ключу вставляет или заменяет
  print("{stock.get("apple") ?? 0} {stock.get("kiwi") ?? -1} {stock.len()}")
  stock.remove("pear")
  for (k, v) in stock.iter().sortBy(p => p.0) { print("{k}={v}") }

  var seen: Set<str> = Set.new()
  print("{seen.insert("a")} {seen.insert("a")} {seen.contains("a")} {seen.len()}")
}
Вывод
[1, 3, 5, 8] first=1 last=8
[10, 30, 50, 80] [5, 8] sum=17
true true false 3
3 -1 3
apple=3
plum=7
true false true 1

Разбор#

  • xs.push(1), xs.sort() изменяют список на месте и поэтому требуют var. map, filter, fold возвращают новое значение.
  • xs.first() возвращает T? — у пустого списка первого элемента нет, и ?? -1 задаёт значение по умолчанию. То же с get у списка и словаря: выход за границы через get не паника, а none.
  • {"apple": 3} — литерал словаря, {:} — пустой словарь (пустые {} — это блок). stock["plum"] = 7 вставляет или заменяет.
  • Set.insert возвращает true, если элемент новый.
  • Итерация по словарю даёт пары (ключ, значение); sortBy упорядочивает их.

Ленивые итераторы и запросы#

oxl✓ проверяется в CI
fn main() io {
  let nums = 1..=10
  let evens = nums.iter().filter(n => n % 2 == 0).map(n => n * n)  // ленивая цепочка: пока ничего не вычислено
  print("{evens.toList()}")  // toList запускает вычисление

  let words = ["pear", "fig", "banana", "kiwi", "apple"]
  let q = from w in words where w.len() > 3 order by w.len() desc, w select "{w}:{w.len()}"  // запрос — тот же конвейер в виде выражения
  print("{q.toList()}")

  let pairs = words.iter().enumerate().skip(1).take(2).toList()
  print("{pairs}")
  let total = (1..=100).iter().takeWhile(n => n * n < 200).fold(0, (a, n) => a + n)
  print("{total}")
  print("{words.iter().map(w => w.len()).max() ?? 0}")
  let byLen = from w in words group by w.len() into g select (g.key, g.count())
  print("{byLen.toList()}")
}
Вывод
[4, 16, 36, 64, 100]
["banana:6", "apple:5", "kiwi:4", "pear:4"]
[(1, "fig"), (2, "banana")]
105
6
[(4, 2), (3, 1), (6, 1), (5, 1)]
  • 1..=10 — диапазон; .iter() превращает коллекцию или диапазон в ленивый iter<T>.
  • filter, map, skip, take, enumerate, takeWhile возвращают новый итератор; вычисление запускают toList(), fold, count, max, for.
  • from w in words where … order by … select … — выражение запроса: то же самое, но читается как SQL. Для коллекций в памяти это ленивый итератор; для таблиц ORM (шаг в туре) тот же синтаксис компилируется в SQL.
  • group by … into g select (g.key, g.count()) группирует; группы идут в порядке первого появления ключа.

Типичные ошибки#

Вызов несуществующего метода — unknown-method (в OxL длина списка — len(), а не length()):

oxl✓ проверяется в CI
fn main() io {
  let xs = [1, 2, 3]
  print("{xs.length()}")
}
error
unknown-method

Тип элемента проверяется строго: положить строку в List<i32> нельзя — type-mismatch:

oxl✓ проверяется в CI
fn main() io {
  var xs: List<i32> = [1, 2]
  xs.push("three")
}
error
type-mismatch

Что запомнить#

  • List, Map, Set — по порядку вставки; поиск возвращает T?.
  • Конвейеры iter ленивы; результат нужно потребовать.
  • Запрос from … select — удобная запись того же конвейера.

Дальше: владение и заимствование.

См. также

OxL 1.0.0-beta · Версия документации 1.0.0-beta© OxwaldLink · сгенерировано из Стандарта, исходников std и руководства