Appearance
迭代
本文档记录 cp 的迭代协议。迭代协议建立在 concept、泛型 variant 和 requires 类型约束之上,不引入运行时多态。
目标是定义统一的 range-for 语义:范围表达式先被解析成一个 iterator,之后循环只依赖 iterator.next()。
基础类型
迭代结束使用标准库 std.core.option 中的泛型 variant 表示:
cp
export module std.core.option;
export variant optional<T> {
none;
some(T);
}optional<T> 不是语法关键字。它是标准库中约定的普通泛型 variant。构造时遵循泛型 variant 规则,必须写完整类型实参:
cp
let end = optional<i32>::none;
let item = optional<i32>::some(1);Iterator 协议
iterator 表示有状态游标。调用 next 会推进游标,并返回本次产生的元素或结束标记。
cp
export module std.core.iter;
import std.core.option;
export concept iterator {
type iter_item;
next(self&) -> optional<iter_item>;
}规则:
iter_item是每次迭代产生的元素类型。next(self&)需要可写self,因为 iterator 本身保存遍历状态。- 返回
.some(value)表示本轮产生一个元素,并且 iterator 已经前进到下一状态。 - 返回
.none表示迭代结束。结束后再次调用next应继续返回.none。 - 按值产生元素。引用迭代、可变引用迭代和借用生命周期不属于当前迭代协议。
例如:
cp
struct range_iter {
current_value: i32;
end_value: i32;
}
impl iterator for range_iter {
type iter_item = i32;
next(self&) -> optional<i32>
{
if(current_value >= end_value) {
return optional<i32>::none;
}
let value = current_value;
current_value += 1;
return optional<i32>::some(value);
}
}Iterable 协议
iterable 表示一个值可以产生 iterator。它通常由容器、范围对象或视图实现。
cp
export module std.core.iter;
export concept iterable {
type iter_type;
type iter_item;
requires (
iter_type: iterator
and iter_type::iter_item == iter_item
);
iter(self&) -> iter_type;
}规则:
iter_type是iter(self)产生的 iterator 类型。iter_type必须实现iterator。iter_type::iter_item必须和iterable::iter_item相同。iter(self&)可以保存必要的当前位置、边界、指针或引用信息。- 只定义可写
self的入口。只读迭代需要通过iter(self const&)、独立 concept 或函数重载规则单独定义。
例如:
cp
struct range {
begin: i32;
end: i32;
}
impl range {
iter(self&) -> range_iter
{
return range_iter{ .current_value = begin, .end_value = end };
}
}
impl iterable for range {
type iter_type = range_iter;
type iter_item = i32;
}范围 for
范围 for 写作:
cp
for(let value : values) {
use(value);
}语义检查先把范围表达式转换成 iterator:
- 令
R = type(values)。 - 如果
R implements iterable,则检查R::iter_type implements iterator,并检查R::iter_type::iter_item == R::iter_item。循环使用values.iter()产生的 iterator。 - 否则,如果
R implements iterator,则直接把values作为一次性 iterator 消费。 - 否则报错:范围表达式必须实现
iterable或iterator。
如果选中的入口需要 self&,但范围表达式只能作为 const 值或 const 引用使用,则报错。实现 iterator 不代表任意当前值都能推进;next(self&) 需要可写 iterator 状态。
取得 iterator 后,range-for 只有一套展开规则:
cp
let __iter = /* values.iter() or values */;
while(true) {
let __next = __iter.next();
match __next {
.some(value) => {
body;
},
.none => {
break;
},
};
}for(const value : values) 只表示循环变量 binding 不可重新赋值,不改变 iterator 的推进方式。
break 和 continue
因为 next 同时完成“取值”和“推进”,continue 不需要额外跳到一个 advance 步骤。
规则:
break离开当前循环,并执行离开作用域所需的清理。continue结束当前 body,进入下一轮循环;下一轮会重新调用__iter.next()。- 带标签的
break label/continue label仍按 flow.md 的标签规则解析。
Iterator 与 Iterable 的关系
iterator 和 iterable 是单向关系:
text
iterable depends on iterator
iterator does not depend on iterable也就是说,一个容器或范围对象实现 iterable,它产生的游标实现 iterator。一个 iterator 本身也可以直接被 range-for 消费,但这表示一次性消费当前游标状态,不表示从头重新遍历某个集合。
cp
for(let value : values) {
// values implements iterable
}
for(let value : values.iter()) {
// values.iter() returns an iterator
}不把“所有 iterator 自动也是 iterable”写成 blanket impl,因为泛型设计不支持以裸类型参数为目标的 blanket impl。range-for 对 iterator 的直接入口是语言层面的解析规则。
内建类型
内建类型通过等价的 iterable 能力接入 range-for:
text
[T; N] implements iterable
str implements iterablestr 第一版按 char 遍历,迭代边界是 str.size(),不是 trailing '\0'。因此包含中间 '\0' 的字符串视图仍会完整遍历其 len 个字符。