Skip to content

std.range ​

区间(Range)迭代与适配器。

yaoxiang
use std.range

区间字面量 ​

写法含义
a..b从 a 到 b,步长 1
a..b..s从 a 到 b,步长 s

区间不包含结束值(左闭右开)。步长可为负,表示递减。

迭代器协议 ​

iter 返回 Result——步长为 0 时是错误路径(E6009),所以要先 unwrap 或显式处理:

yaoxiang
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 的迭代器一致。

yaoxiang
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:

yaoxiang
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 ​

yaoxiang
iter: (r: Range(Int)) -> Result(Iterator(Any), Error)

由区间创建迭代器。

  • r —— 区间,如 1..6 或 3..0..-1

返回:成功为 Result.ok(迭代器);步长为 0 时为 Result.err,code 为 E6009。

yaoxiang
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 ​

yaoxiang
has_next: (it: Iterator(Any)) -> Bool

是否还有未消费的元素。

会移动迭代器。

yaoxiang
use std.assert
use std.range
use std.result

main: () -> Void = {
    it = result.unwrap(range.iter(1..4))
    assert(range.has_next(it))
}

next ​

yaoxiang
next: (it: &Iterator(Any)) -> Any

取出当前元素并把内部游标前移一位。

返回:当前元素;迭代结束时返回 Void。

会移动迭代器。

yaoxiang
use std.assert
use std.range
use std.result

main: () -> Void = {
    it = result.unwrap(range.iter(1..4))
    assert(range.next(it) == 1)
}

递减区间同样支持:

yaoxiang
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 ​

yaoxiang
contains: (r: Range(Int), x: Int) -> Result(Bool, Error)

判断 x 是否落在区间内。

  • r —— 区间
  • x —— 待判定值

返回:Result.ok(Bool)。结束值为开区间(不包含);带步长时只匹配与步长对齐的元素。

yaoxiang
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 ​

yaoxiang
abort_invalid_step: (r: Range(Int)) -> Any

步长非法的中止钩子,供 for ... in 消费到步长为 0 的区间时调用。

总是抛出 E6007,消息为 Range step must be non-zero (for/in consumption)。正常代码无需直接调用。

yaoxiang
use std.range

main: () -> Void = {
    // 直接用 iter 会得到 Err,不需要走这个钩子
    r = range.iter(1..3)
}

适配器 ​

map 与 filter 返回惰性适配器——它们不立即计算,需由 collect / reduce / for_each / for ... in 消费后才产生结果。

map ​

yaoxiang
map: (it: Iterator(Any), f: (Any) -> Any) -> Iterator(Any)

把 f 映射到每个元素上,返回新的惰性迭代器。

yaoxiang
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 ​

yaoxiang
filter: (it: Iterator(Any), p: (Any) -> Bool) -> Iterator(Any)

保留使 p 为真的元素,返回新的惰性迭代器。

yaoxiang
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)
}

适配器可链式组合:

yaoxiang
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 ​

yaoxiang
collect: (it: Iterator(Any)) -> Vec(Any)

消费迭代器,把全部元素收集为 List。

yaoxiang
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 ​

yaoxiang
reduce: (it: Iterator(Any), init: Any, f: (Any, Any) -> Any) -> Any

消费迭代器并折叠。

  • it —— 迭代器
  • init —— 初始累加值
  • f —— 归约函数 (累加值, 元素) -> 新累加值

注意参数顺序与 std.list.reduce 不同:本模块是 (迭代器, 初值, 函数),std.list 是 (列表, 函数, 初值)。

yaoxiang
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 ​

yaoxiang
for_each: (it: Iterator(Any), f: (Any) -> Void) -> Void

对每个元素执行 f,用于副作用。

yaoxiang
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。

相关 ​