8.0 KiB
08 · 控制流
0/20 项已确认。当前推进 08-01;本分类尚未完成选择。
本页整理原讨论的问题、验收要求和候选方案。勾选代表讨论中已确认的规则,不代表编译器或运行时已经实现。
08-01 控制结构与值的关系
- 待讨论
明确条件、匹配、循环中哪些能作为表达式,以及结果能否被忽略;给出允许和不允许的使用位置。
08-02 条件分支的完整规则
- 待讨论
明确分支写法、结果来源、缺少 else 的行为,以及不同出口如何形成结果。结果兼容性依赖【类型系统】。
08-03 条件与真值判断
- 待讨论
明确条件接受哪些值、是否转换或允许定制,以及不合法条件如何失败。定制机制依赖【对象与类型模型/定制协议】。
08-04 短路与条件求值
- 待讨论
明确是否支持短路逻辑运算、返回布尔值还是操作数,以及哪些子表达式不会执行。
08-05 循环形式与正常结束
- 待讨论
明确支持哪些循环、条件何时检查、零次执行和正常耗尽的行为;若循环有值,定义正常结束的结果。
08-06 遍历与迭代协议
- 待讨论
明确遍历怎样取得下一项、如何识别结束,以及遍历失败和提前退出时的行为。协议形态依赖【定制协议】。
08-07 分支及循环的绑定与作用域
- 待讨论
明确局部绑定的可见范围、循环变量在各次迭代间的关系、循环后的可见性;检查闭包捕获的交互,依赖【名称与作用域/函数】。
08-08 break
- 待讨论
明确合法目标、是否携带值、嵌套时如何选择目标,以及目标不存在或值不合法时的行为。
08-09 continue
- 待讨论
明确合法目标、跳转后执行循环的哪个阶段、是否支持指定外层循环,以及非法位置的行为。
08-10 return
- 待讨论
明确返回目标、无返回值的行为、函数末尾是否隐式返回,以及在嵌套函数和生成器中的含义。依赖【函数】。
08-11 模式的种类与匹配含义
- 待讨论
明确支持哪些模式、每种模式如何判断成功,以及不支持的形式如何处理。结构读取与相等判断依赖【对象与类型模型/运算符】。
08-12 匹配顺序与守卫条件
- 待讨论
明确分支选择顺序、守卫何时执行、失败后是否继续,以及重叠模式和副作用的行为。
08-13 匹配覆盖与失败
- 待讨论
明确是否要求穷尽、是否允许默认分支、无分支命中的行为,以及不可达分支如何处理。静态检查能力依赖【类型系统】。
08-14 模式中的变量绑定
- 待讨论
明确绑定与已有值比较如何区分、重复变量与组合模式是否合法,以及失败匹配是否留下绑定。
08-15 生成器的基本控制模型
- 待讨论
决定是否支持生成器;若支持,明确创建、启动、暂停、恢复和结束,以及如何交付生成值和最终结果。函数调用形式依赖【函数】。
08-16 生成器的提前终止与生命周期
- 待讨论
若支持生成器,明确主动关闭、内部失败、恢复已结束生成器及重入的行为;明确遗弃生成器时对清理作何保证。依赖【资源管理/内存管理】。
08-17 异常与执行路径
- 待讨论
明确异常怎样穿过条件、循环、匹配和函数,在哪里可以被接住,以及捕获后从哪里继续。异常表示与匹配规则依赖【异常与错误处理】。
08-18 非正常退出与资源清理
- 待讨论
明确 break、continue、return、异常和生成器关闭触发哪些清理、执行顺序,以及清理自身再次退出或失败时谁生效。依赖【异常与错误处理/资源管理】。
08-19 控制流边界与非法跨越
- 待讨论
明确跳转能否跨越函数、闭包、生成器或清理区域,是否支持额外的非局部跳转;给出非法跨越的诊断原则。若其他分类引入异步边界,也在此核对。
08-20 跨分类一致性验收
- 待讨论
用一组涵盖嵌套分支、循环退出、匹配失败、生成器暂停及清理冲突的例子核对最终规则;所有相关依赖均已解决或明确不适用,没有相互矛盾的决定。
当前问题的方案与语言对照
以下沿用原讨论材料;建议和参考语言的做法均不自动成为本语言规则。
当前待选的 08-01 是:条件、匹配和循环能否直接产生值?产生的值能否被忽略?
相关语言提供了几种不同的安排:
| 语言 | 规则与小例子 | 取舍及对我们的启发 |
|---|---|---|
| Python | if、match、for、while 是语句;另有条件表达式:x = a if ready else b。语句规则、条件表达式 |
简短选择可以直接产生值;需要多步计算时,通常回到分支赋值或辅助函数。说明“语句为主”仍可以单独提供条件表达式。 |
| JS/TS | if、switch 和循环是语句;条件表达式写成 const x = ready ? a : b。TS 在此沿用 JS 的执行语义,并增加静态检查,不是另一套运行时。ECMAScript 语句、条件表达式、TS 类型擦除 |
与 Python 类似:简单选择紧凑,多步分支不直接作为表达式组合。启发是要区分“单独的条件运算符”与“整个分支块都能产生值”。 |
| Go | if、switch、for 是语句,也没有 ?:;通常先声明变量,再在分支中赋值。Go 规范、官方 FAQ |
选择结果与执行步骤使用同一种分支结构,规则较少;代价是简单初始化也可能需要多行。适合参考方案 A。 |
| Rust | if、match 是表达式,如 let x = if ready { a } else { b };。loop 可以用 break value 交付结果。分支规则、匹配规则、循环规则 |
多步计算也能直接组合、初始化变量;需要处理各出口的结果兼容性。但 Rust 的 while、for 正常结束得到 (),不能像 loop 那样直接 break value。 表达式化仍然可以区分不同循环。 |
关于“忽略结果”,Rust 明确支持通过表达式语句求值并丢弃结果;这说明能够产生值,不必意味着必须接住值。Rust 表达式语句
回到我们的三个候选方向:
- A:控制结构主要是语句。 简单条件是否另设表达式,需要明确;Python/JS 和 Go 在这里就有区别。
- B:
if、匹配可以产生值,循环是语句。 分支计算容易组合,循环无需引入结果规则。 - C:分支和循环都可以产生值。 查找、重试可以直接交付结果,但需要定义哪些循环支持、正常耗尽时得到什么。
我的建议是 B,并允许忽略控制表达式的结果。 它能让多步分支直接初始化变量,又暂时不引入循环结果的额外规则。这只是建议,尚未记为决定;分支缺少 else 等细节仍在 08-02 处理。
你更倾向 A、B、C 哪一种?对于能够产生值的控制结构,是否允许直接执行并忽略结果?
讨论来源
《语言设计 08:控制流》,整理日期 2026-10-28。章节编号沿用原清单。