std.range
Итерация по диапазонам (Range) и адаптеры.
use std.rangeЛитералы диапазонов
| Запись | Значение |
|---|---|
a..b | от a до b с шагом 1 |
a..b..s | от a до b с шагом s |
Диапазон не включает конечное значение (полуоткрытый интервал). Шаг может быть отрицательным — это означает убывание.
Протокол итератора
iter возвращает Result — при шаге 0 срабатывает ветка ошибки (E6009), поэтому нужно сначала вызвать unwrap или явно обработать результат:
use std.assert
use std.list
use std.range
use std.result
main: () -> Void = {
it = result.unwrap(range.iter(1..4))
assert(range.has_next(it))
}Семантика перемещения: сигнатуры
has_nextиnextне содержат&, поэтому они перемещают итератор. Следовательно, при каждом использовании итератор нужно создавать заново либо сразу обходить черезfor ... in. Это согласуется с итераторомstd.list.
use std.assert
use std.range
use std.result
main: () -> Void = {
// Создаём итераторы по одному
a = result.unwrap(range.iter(1..3))
assert(range.has_next(a))
b = result.unwrap(range.iter(1..3))
assert(range.next(b) == 1)
}Для повседневного обхода просто используйте for ... in:
use std.assert
use std.list
main: () -> Void = {
nums = [1, 2, 3]
mut sum = 0
for x in nums {
sum = sum + x
}
assert(sum == 6)
}Список функций
| Функция | Сигнатура |
|---|---|
iter | (r: Range(Int)) -> Result(Iterator(Any), Error) |
has_next | (it: Iterator(Any)) -> Bool |
next | (it: &Iterator(Any)) -> Any |
contains | (r: Range(Int), x: Int) -> Result(Bool, Error) |
abort_invalid_step | (r: Range(Int)) -> Any |
map | (it: Iterator(Any), f: (Any) -> Any) -> Iterator(Any) |
filter | (it: Iterator(Any), p: (Any) -> Bool) -> Iterator(Any) |
collect | (it: Iterator(Any)) -> Vec(Any) |
reduce | (it: Iterator(Any), init: Any, f: (Any, Any) -> Any) -> Any |
for_each | (it: Iterator(Any), f: (Any) -> Void) -> Void |
Протокол итератора
iter
iter: (r: Range(Int)) -> Result(Iterator(Any), Error)Создаёт итератор из диапазона.
r— диапазон, например1..6или3..0..-1.
Возвращает: при успехе — Result.ok(итератор); при шаге 0 — Result.err, code равен E6009.
use std.assert
use std.range
use std.result
main: () -> Void = {
it = result.unwrap(range.iter(1..4))
assert(range.has_next(it))
}has_next
has_next: (it: Iterator(Any)) -> BoolЕсть ли ещё не потреблённые элементы.
Перемещает итератор.
use std.assert
use std.range
use std.result
main: () -> Void = {
it = result.unwrap(range.iter(1..4))
assert(range.has_next(it))
}next
next: (it: &Iterator(Any)) -> AnyИзвлекает текущий элемент и сдвигает внутренний курсор на одну позицию вперёд.
Возвращает: текущий элемент; при завершении итерации — Void.
Перемещает итератор.
use std.assert
use std.range
use std.result
main: () -> Void = {
it = result.unwrap(range.iter(1..4))
assert(range.next(it) == 1)
}Убывающие диапазоны тоже поддерживаются:
use std.assert
use std.range
use std.result
main: () -> Void = {
desc = result.unwrap(range.iter(3..0..-1))
assert(range.next(desc) == 3)
}contains
contains: (r: Range(Int), x: Int) -> Result(Bool, Error)Проверяет, попадает ли x в диапазон.
r— диапазон.x— проверяемое значение.
Возвращает: Result.ok(Bool). Конечное значение — открытая граница (не включается); при заданном шаге совпадают только значения, выровненные по шагу.
use std.assert
use std.range
use std.result
main: () -> Void = {
assert(result.unwrap(range.contains(1..10, 5)))
assert(!result.unwrap(range.contains(1..10, 10))) // Конечное значение не входит
assert(result.unwrap(range.contains(0..10..2, 4))) // Выровнено по шагу
assert(!result.unwrap(range.contains(0..10..2, 3))) // Не выровнено
}abort_invalid_step
abort_invalid_step: (r: Range(Int)) -> AnyХук аварийного завершения при недопустимом шаге; вызывается, когда for ... in потребляет диапазон с шагом 0.
Всегда возбуждает E6007 с сообщением Range step must be non-zero (for/in consumption). Обычному коду вызывать его напрямую не нужно.
use std.range
main: () -> Void = {
// Прямое использование iter вернёт Err, обходить этот хук не нужно
r = range.iter(1..3)
}Адаптеры
map и filter возвращают ленивые адаптеры — они не вычисляются немедленно; результат получается только после их потребления через collect / reduce / for_each / for ... in.
map
map: (it: Iterator(Any), f: (Any) -> Any) -> Iterator(Any)Применяет f к каждому элементу и возвращает новый ленивый итератор.
use std.assert
use std.list
use std.range
use std.result
main: () -> Void = {
doubled = range.collect(range.map(result.unwrap(range.iter(1..4)), x => x * 2))
assert(list.len(doubled) == 3)
assert(doubled[0] == 2)
}filter
filter: (it: Iterator(Any), p: (Any) -> Bool) -> Iterator(Any)Оставляет элементы, для которых p истинна, и возвращает новый ленивый итератор.
use std.assert
use std.list
use std.range
use std.result
main: () -> Void = {
big = range.collect(range.filter(result.unwrap(range.iter(1..6)), x => x > 3))
assert(list.len(big) == 2)
assert(big[0] == 4)
}Адаптеры можно компоновать в цепочку:
use std.assert
use std.list
use std.range
use std.result
main: () -> Void = {
r = 1..6
chained = range.collect(range.map(range.filter(result.unwrap(range.iter(r)), x => x % 2 == 0), x => x * 10))
// Семантика значений: `chained` потребляется при чтении по индексу, поэлементно связывается с локальными переменными
first = chained[0]
second = chained[1]
assert(first == 20)
assert(second == 40)
}collect
collect: (it: Iterator(Any)) -> Vec(Any)Потребляет итератор и собирает все элементы в List.
use std.assert
use std.list
use std.range
use std.result
main: () -> Void = {
xs = range.collect(result.unwrap(range.iter(1..4)))
assert(list.len(xs) == 3)
}reduce
reduce: (it: Iterator(Any), init: Any, f: (Any, Any) -> Any) -> AnyПотребляет итератор и сворачивает его.
it— итератор.init— начальное значение аккумулятора.f— функция свёртки(аккумулятор, элемент) -> новый_аккумулятор.
Обратите внимание, что порядок аргументов отличается от
std.list.reduce: в этом модуле он(итератор, начальное_значение, функция), тогда как вstd.list—(список, функция, начальное_значение).
use std.assert
use std.range
use std.result
main: () -> Void = {
total = range.reduce(result.unwrap(range.iter(1..6)), 0, (acc, x) => acc + x)
assert(total == 15)
}for_each
for_each: (it: Iterator(Any), f: (Any) -> Void) -> VoidВыполняет f для каждого элемента; используется ради побочных эффектов.
use std.assert
use std.range
use std.result
main: () -> Void = {
// Выводит 1, 2, 3
range.for_each(result.unwrap(range.iter(1..4)), x => println(x))
assert(true)
}Замыкания в настоящее время не могут захватывать и перезаписывать внешнюю переменную
mut, поэтому накапливать значение черезfor_eachне получится (будет ошибкаE1001) — для накопления используйтеreduce.
Связанные разделы
std.list— списки и их итераторы.std.result— распаковка возвращаемых значенийiter/contains.- Справочник по кодам ошибок —
E6009недопустимый шаг.
