# 09 · 集合与访问协议 0/22 项已确认。当前推进 09-01;本分类尚未完成选择。 本页整理原讨论的问题、验收要求和候选方案。勾选代表讨论中已确认的规则,不代表编译器或运行时已经实现。 ## 09-01 能力如何组织 - [ ] 待讨论 确定下标、迭代、成员判断等能力独立提供、按类别打包,还是允许相互推导;明确组合约束。 ## 09-02 下标接受什么 - [ ] 待讨论 确定位置、键、多维下标及其他选择器的支持范围,以及不支持的下标如何失败。 ## 09-03 读取失败与缺失 - [ ] 待讨论 确定键不存在、无法读取时的行为,以及如何区分“缺失”和“存储的空值”。依赖「错误处理与结果类型」。 ## 09-04 下标写入与删除 - [ ] 待讨论 确定是否分别支持、键不存在时如何处理,以及只读容器上的行为。 ## 09-05 位置索引规则 - [ ] 待讨论 确定索引起点、可接受的索引值、负索引、越界与空集合行为。 ## 09-06 文本索引单位 - [ ] 待讨论 确定字符串是否支持位置访问,以及访问单位和边界。依赖「字符串与文本」。 ## 09-07 切片范围规则 - [ ] 待讨论 确定端点包含关系、默认端点、步长、反向切片、越界与非法步长行为。 ## 09-08 切片结果语义 - [ ] 待讨论 确定副本、共享视图或惰性结果的选择规则,以及原集合变化的影响。 ## 09-09 切片写入与删除 - [ ] 待讨论 确定支持范围、替换长度要求、重叠操作及失败后的集合状态。 ## 09-10 长度与有限性 - [ ] 待讨论 确定哪些对象提供长度,未知或无限长度如何表达,长度是否允许通过遍历计算。 ## 09-11 获得迭代器与重复遍历 - [ ] 待讨论 确定如何开始遍历,区分可重复遍历对象与单次消费对象,以及多个遍历是否独立。 ## 09-12 取下一项与迭代结束 - [ ] 待讨论 确定元素、正常结束和读取失败的区别,以及结束后再次读取的行为。依赖「错误处理与结果类型」。 ## 09-13 遍历内容与顺序 - [ ] 待讨论 确定映射等容器产出什么,各类容器承诺哪些顺序,以及顺序是否稳定。 ## 09-14 遍历期间修改集合 - [ ] 待讨论 确定允许的修改、观察到的结果,以及冲突检测和失败行为。 ## 09-15 提前结束与资源释放 - [ ] 待讨论 确定退出循环、异常和部分消费时的迭代器处理。依赖「资源管理与控制流」。 ## 09-16 成员判断的含义 - [ ] 待讨论 确定判断键、值还是元素,采用何种匹配规则,以及缺失时的结果。依赖「值与相等性」。 ## 09-17 成员判断的默认实现 - [ ] 待讨论 确定是否允许退回遍历,以及单次流、无限数据和遍历失败时的行为。 ## 09-18 解包的数据来源 - [ ] 待讨论 确定解包依赖迭代、位置访问还是独立协议,以及消费顺序。 ## 09-19 解包数量与失败 - [ ] 待讨论 确定数量不足、数量过多、剩余项捕获及无限输入的行为;明确失败时已消费数据和已绑定变量的状态。依赖「绑定与赋值」。 ## 09-20 自定义容器如何接入 - [ ] 待讨论 确定用户需要提供哪些操作、哪些有默认行为,以及缺失或冲突如何报告。依赖「类型系统与定制协议」。 ## 09-21 异步遍历的支持边界 - [ ] 待讨论 确定本轮是否支持;若支持,明确与同步遍历、取消和清理的关系。依赖「并发与异步」。 ## 09-22 跨协议一致性验收 - [ ] 待讨论 检查索引、长度、切片、迭代、成员判断和解包之间的约束;核对相关分类决定,解决冲突。 ## 当前问题的方案与语言对照 以下沿用原讨论材料;建议和参考语言的做法均不自动成为本语言规则。 当前仍是 **09-01:下标、迭代、成员判断等能力如何组织**。核心问题是:支持一种能力,是否自动获得其他能力? 下面的规则来自语言或标准库文档;其中的优缺点是我们的取舍分析,不代表已经确认的历史设计动机。 | 语言 | 相关规则与具体行为 | 好处、代价及启发 | |---|---|---| | **Python** | 能力分别定制,但有回退:没有 `__contains__` 时,`x in obj` 会尝试迭代,再尝试旧式位置访问。因此 `2 in iter([1, 2, 3])` 为真,同时消费迭代器到 `2`。标准库也提供 `Sequence` 等组合契约。[数据模型](https://docs.python.org/3/reference/datamodel.html#object.__contains__)、[容器抽象](https://docs.python.org/3/library/collections.abc.html) | 定制操作较少也能获得便利;但成员判断可能隐含消费和长时间搜索。说明“独立能力”“组合契约”“默认推导”可以分层存在。 | | **JS** | 迭代通过 `Symbol.iterator`,与下标访问分开。`{0: "a", length: 1}` 能读取 `[0]`,却不能直接用于 `for...of`。`Map` 通过 `.has(k)` 判断键是否存在;JS 的 `in` 检查对象属性,并非通用集合成员判断。[迭代协议](https://tc39.es/ecma262/2025/multipage/abstract-operations.html#sec-getiterator)、[属性判断](https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-relational-operators-runtime-semantics-evaluation)、[Map.has](https://tc39.es/ecma262/2025/multipage/keyed-collections.html#sec-map.prototype.has) | 能力边界较明确;不同容器的查询接口也可能不同。启发是:统一语法与统一能力是两个决定。 | | **TS** | 用静态类型分别表达能力,例如 `ArrayLike` 描述数字下标和长度,`Iterable` 描述可迭代;只有前者不保证满足后者。执行仍依赖生成的 JS、运行环境及编译配置,TS 没有独立运行时。[对象类型](https://www.typescriptlang.org/docs/handbook/2/objects.html)、[迭代类型](https://www.typescriptlang.org/docs/handbook/iterators-and-generators.html) | 可以提前检查算法需要的能力;类型声明仍需与运行行为一致。我们可以先决定语义,再决定是否静态检查。 | | **Go** | 内置下标适用于规定的类型,不能靠给任意结构体添加方法来重载 `[]`;`range` 有独立规则,Go 1.23 起支持规定签名的迭代函数。例如通道可以被 `range` 遍历,却不能下标访问。[语言规范](https://go.dev/ref/spec) | 内置规则集中明确;自定义容器接入下标语法的空间较小。说明访问与遍历也可以采用不同的扩展机制。 | | **Rust** | `Index` 与 `IntoIterator` 是分开的 trait。自定义类型只实现 `Index`,不会因此获得 `for` 遍历。通用搜索可显式写成 `iter.any(|x| x == 42)`,会推进迭代器直到匹配或结束。[Index](https://doc.rust-lang.org/std/ops/trait.Index.html)、[IntoIterator](https://doc.rust-lang.org/std/iter/trait.IntoIterator.html)、[any](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.any) | 能力要求明确,搜索也能复用;自定义类型需要提供对应能力。说明“提供通用算法”不必意味着“自动赋予另一项协议”。 | 这些语言都混合使用了多种机制,不能简单把整门语言归为某一个方案。我们当前仍选这三个方向之一: - **A.按类别打包**:序列、映射等各自规定必需能力;特殊容器可能需要适配。 - **B.能力独立**:可下标不自动意味着可迭代,可迭代不自动意味着支持成员判断;通用搜索可以显式调用。 - **C.能力独立并允许默认推导**:例如没有专门成员判断时,自动遍历;具体回退规则在后续任务明确。 **我建议 B**:目前语言用途尚未确定,先独立表达能力,可以容纳数组、映射和单次输入流;常用能力仍可组合成契约。代价是自定义容器可能要多提供几个操作。这只是建议,尚未成为决定。 你倾向 **A、B,还是 C**? ## 讨论来源 《语言设计 09:集合与访问协议》,整理日期 2026-10-28。章节编号沿用原清单。