
编程语言编译器开发工具【免费下载链接】xgoXGo is a programming language that reads like plain English. But its also incredibly powerful — it lets you leverage assets from C/C, Go, Python, and JavaScript/TypeScript, creating a unified software engineering ecosystem. Our vision is to enable everyone to become a builder of the world.项目地址https://gitcode.com/gh_mirrors/go/xgo点击查看免费下载XGo 是 Go 语言的超集式编程语言其语法贴近自然语言同时完整保留了 Go 的类型系统与工具链。本文以 XGo 的核心循环语句for为主题系统讲解其四种形式裸for、条件for、C 风格for、XGo 原生for..in并深入剖析for..in的绑定规则、可选if过滤、全部可迭代表达式类别及XGo_Enum自定义迭代协议。读完本文你将掌握 XGo 中迭代循环的完整写法、每种可迭代类型的取值语义以及如何为自己的类型接入for..in生态并理解其在编译器内部的实现路径。OverviewXGo 的单一循环关键字XGo 只有一个循环关键字for共四种形式裸forbarefor无限循环条件forconditionfor相当于其他语言的whileC 风格forC-stylefor经典三子句循环for..inXGo 原生的遍历值语法可附带可选的if过滤子句。前三种形式与 Go 完全一致没有任何变化第四种是 XGo 独有的迭代语法。文档 doc/for.md 明确指出for..in是 XGo 中推荐的迭代方式它直接覆盖了 Go 中由for range处理的所有场景。逐值迭代for each value是循环中最常见的意图for..in正是围绕这一意图直接设计的for v in expr依次把expr的每个值绑定到v当同时需要键索引与值时for k, v in expr按键/索引在前、值在后的顺序绑定二者。for..in可作用于非常广泛的可迭代表达式整数、数组、切片、字符串、映射、通道、区间表达式start:end:step、迭代器函数以及任何暴露了返回迭代器函数的XGo_Enum方法的类型。XGo 的类与对象模型需要一种机制让用户自定义类型能以最小代价参与for..in迭代而不必实现类似sort.Interface那样的多方法协议。XGo_Enum()约定正是为此而生它为任意类型提供了一个单一、极简的挂钩点。裸for无限循环for { // ... }省略条件即构成无限循环必须通过break或return跳出。条件for相当于whilesum : 0 i : 1 for i 100 { sum i i } echo sum // 5050条件for等价于其他语言中的while循环只要布尔条件为true就持续执行循环体。条件两侧不加圆括号花括号始终是必需的。C 风格for经典三子句for i : 0; i 10; i 2 { if i 6 { continue } echo i // 0 // 2 // 4 // 8 }这是传统的三子句形式初始化语句、条件、循环后语句三者以;分隔。相比条件for它更安全因为计数器更新被固定在循环头部不容易遗漏。for..inXGo 原生迭代语法语法for..in的形式为for identifiers in expr { ... }并可在被迭代表达式与左花括号之间插入可选的if condition。支持两种标识符形式for v in expr { ... } // 绑定值 for k, v in expr { ... } // 绑定键/索引与值for..in总是在循环体作用域内声明新的变量。不需要使用的变量按 XGo/Go 的常规规则写作_。值得注意的是for in expr零个标识符是非法的。如果迭代纯粹是为了副作用而不接触产出值请改用for expr {}风格的其他构造。从语法层面看for..in在 AST 中由 ForPhraseStmt 表示它内嵌一个 ForPhrase 结构其中Key、Value分别对应in子句前后的标识符X是被迭代的表达式Cond是可选过滤条件——这与文档描述的语法结构完全对应。绑定规则当只绑定一个变量时for v in expr绑定的是值当绑定两个变量时for k, v in expr先绑定键/索引再绑定值。该规则对所有可迭代类别统一成立对于产出两个分量键/索引与值的类别for v in expr绑定值并丢弃键/索引for k, v in expr二者都绑定键/索引在前。对于只产出单个分量的类别该分量被当作值由for v in expr直接绑定此时使用for k, v in expr是编译错误因为没有第二个分量可绑。可选的if过滤子句for..in接受可选的尾随if子句。存在该子句时循环体只对条件求值为true的元素执行未通过条件的元素被跳过不进入循环体。过滤表达式可以引用in子句绑定的标识符。numbers : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] for num in numbers if num%3 0 { echo num // 0 // 3 // 6 // 9 } for num in :10 if num%3 0 { echo num // 0 // 3 // 6 // 9 }第二个例子把区间表达式:10等价于0:10作为迭代源展示了for..in与区间表达式组合的简洁性。可迭代表达式for..in子句中的expr可以是下列之一int—— 迭代连续的索引0, 1, ..., n-1。n等价于区间表达式:n即int是start 与 step 均取默认值的区间表达式特例。array、slice、string、map、chan—— Go 标准容器/通道类型。迭代string产出rune键/索引为字节偏移量迭代map产出值键/索引为 map 的 key迭代chan只产出接收到的值没有键/索引。区间表达式写作start:end、:end或start:end:step—— XGo 原生的数值区间与任何变量的类型无关。start省略时默认为0step省略时默认为1且不能为0。start:end产出半开序列start, start1, ..., end-1start:end:step产出start, startstep, start2*step, ...对正step而言直到值仍小于end对负step而言直到值仍大于end。start与end可以是任意公共整数类型的表达式。区间表达式不是一等值只能直接作为in子句中的expr出现。满足以下迭代器签名的funcfunc(yield func() bool)func(yield func(V) bool)func(yield func(K, V) bool)任何带XGo_Enum() F方法的类型T或*T其中F是上面三种迭代器函数类型之一。XGo_Enum不接收参数且恰好返回一个值。对于第 5 类编译器会把in子句重写为迭代expr.XGo_Enum()而不是expr本身然后再套用第 4 类的规则。解析顺序编译器首先检查expr的类型是否为内建可迭代类别int、array、slice、string、map、chan、func或区间表达式如果不是再在类型或其指针类型上查找XGo_Enum() F方法若两者都不适用则该表达式不可迭代编译失败。从源码层面看这个重写为expr.XGo_Enum()的过程在编译器中确实存在测试用例 cl/_testxgo/for-in/out.go 展示了for user in doc.users被编译为for user : range doc.XGo_Elem(users).XGo_Enum()cl/expr.go 中compileCondExpr对 DQL 结点集调用cb.MemberVal(XGo_Enum, 0, xExpr).CallWith(0, 1, 0, xExpr)正是把XGo_Enum()作为迭代入口再以闭包形式的yield驱动遍历。各类别语义表下表定义了对每种类别for v in expr与for k, v in expr分别绑定什么。类别产生的分量for v in expr绑定for k, v in expr绑定int仅索引索引非法只有一个值array/slice索引、元素元素索引、元素string字节索引、runerune字节索引、runemap键、值值键、值chan仅值值非法只有一个值区间表达式start:end:step逐次递进的值逐次递进的值非法只有一个值func(yield func() bool)无非法没有值非法没有值func(yield func(V) bool)仅值值非法只有一个值func(yield func(K, V) bool)键、值值丢弃键键、值带XGo_Enum() F的T视F而定视F而定视F而定各类别示例数组、切片、字符串、映射、通道for v in [1, 2, 3] { echo v // 1, 2, 3 } for i, v in [1, 2, 3] { echo i, v // 索引, 元素 } for k, v in {a: 1, b: 2} { echo k, v // 键, 值 } for v in {one: 1, two: 2} { echo v // 1, 2 } for c in héllo { echo c // rune而非字节索引 } ch : ... // ch 是一个通道 for v in ch { echo v }for k, v in ch是编译错误通道只产出一个值。整数for i in 5产出连续索引0, 1, 2, 3, 4等价于for i in :5见下文。for i in :5 { echo i // 0, 1, 2, 3, 4 }for k, v in 5是编译错误int只产出一个值。区间表达式区间表达式start:end:step是 XGo 原生的。它从start默认0开始逐步推进step默认1不能为0负step向下计数直到不包含end。for v in 1:10 { echo v // 1, 2, ..., 9 } for v in :10 { echo v // 0, 1, ..., 9start 默认为 0 } for v in :10:2 { echo v // 0, 2, 4, 6, 8 } for v in 10:0:-1 { echo v // 10, 9, ..., 1 }for k, v in 1:10:2是编译错误区间表达式只产出一个值。在编译器实现层面区间表达式在 parser/parser.go 的parseRangeExpr中被解析为ast.RangeExpr{First, Last, Expr3}First、Last、Expr3分别对应start、end、step随后的编译阶段cl/stmt.go 的toForStmt会把它转换成一个普通for循环并使用_xgo_k、_xgo_step、_xgo_end三个内部变量来保存当前值、步长与终点。测试用例 cl/_testxgo/rangeexpr/in.xgoprintln [x for x in 0:3:1]以及 parser/_testdata/rangeexpr1、parser/_testdata/rangeexpr2、parser/_testdata/rangeexpr3 等解析测试目录均覆盖了区间表达式的行为。迭代器函数funcfor..in在只给一个变量时绑定值分量并在存在键时丢弃键。for v in Seq { // Seq: func(yield func(int) bool) echo v } for k, v in Seq2 { // Seq2: func(yield func(string, int) bool) echo k, v } for v in Seq2 { // 键被丢弃只绑定值 echo v }零值迭代器func(yield func() bool)没有可绑定的东西此时for v in ...是编译错误。带XGo_Enum()的对象任何带有XGo_Enum() F方法的类型都可被迭代效果等同于直接迭代expr.XGo_Enum()——for..in会套用F所属的func签名的规则。type Tree struct { // ... } func (t *Tree) XGo_Enum() func(func(int) bool) { return func(yield func(int) bool) { // 中序遍历为每个元素调用 yield(v) } } tree : new(Tree) ... for v in tree { echo v }双值的XGo_Enum遵循与上述相同的双值规则type OrderedMap struct { // ... } func (m *OrderedMap) XGo_Enum() func(func(string, int) bool) { return func(yield func(string, int) bool) { // 按插入顺序迭代 } } om : new(OrderedMap) ... for k, v in om { echo k, v }这一约定的真实使用案例见 cl/_testxgo/for-in/in.xgoDQLXGo 的 DOM/文档查询语言对象doc.users通过内部生成的XGo_Elem(users).XGo_Enum()迭代器接入for..in其编译产物在 cl/_testxgo/for-in/out.go 中可查。类似的XGo_Enum生成逻辑还遍布 dql 与 encoding 各子包如 dql/fs/fs.go、dql/golang/golang.go、dql/json/json.go、encoding/yaml/yaml.go 等它们都借助该协议让查询结果可被for..in直接遍历。for..in搭配ifnumbers : [1, 3, 5, 7, 11, 13, 17] sum : 0 for x in numbers if x 5 { sum x } echo sum // 48过滤在值以及键若存在绑定之后应用因此过滤表达式可以引用任一标识符names : [Sam, Peter, Alice] for i, name in names if i 0 { echo i, name // 1 Peter // 2 Alice }编译器对if子句的实现可从 cl/stmt.go 的compileForPhraseStmt中看到当存在Cond时编译期在循环体内用cb.If()/cb.Then()包裹条件判断仅当条件成立才编译执行循环体语句——即每轮先绑定循环变量、再求值过滤条件、最后决定是否进入循环体的语义。限制Restrictionsfor k, v in expr要求expr的迭代协议产出两个分量array、slice、string、map、func(yield func(K, V) bool)或返回其中之一的XGo_Enum()。将其应用于int、chan、区间表达式或func(yield func(V) bool)是编译错误。for v in expr要求至少产出一个分量。将其应用于func(yield func() bool)或返回该类型的XGo_Enum()是编译错误。区间表达式的start省略时默认为0step省略时默认为1且不能为0—— 字面量0步长是编译错误非常量求值为0的步长是运行时错误。区间表达式只能直接作为in子句的expr出现 —— 它不是一等值不能被赋值、传递或存储。XGo_Enum必须不接收参数、恰好返回一个值且返回类型是三种迭代器签名之一。任何其他签名的、名为XGo_Enum的方法都不满足该协议此时expr被当作不可迭代。方法集规则与 Go 一致定义在*T上的XGo_Enum只有当类型T的值可寻址addressable时才对该值可见与任何其他指针接收者方法完全相同。if过滤器每轮迭代求值一次时机在该轮循环变量绑定之后、循环体执行之前。从语法到机器码for..in的编译路径for..in的完整生命周期清晰贯穿 XGo 编译器的三层结构可帮助开发者理解其行为边界词法/语法层scanner/gop.go 提供in等关键字与:区间分隔符的词法识别parser/parser.go 的parseRangeExpr处理start:end[:step]区间表达式并将其与for子句组装为 ForPhraseStmt 节点。AST 层ast/ast_xgo.go 的ForPhrase承载Key/Value/X/Cond四个字段ast/walk.go 中的遍历逻辑保证后续编译器各阶段能统一访问该节点。代码生成层cl/stmt.go 的compileRangeStmt与 cl/stmt.go 的compileForPhraseStmt分别处理 Go 风格for range与 XGo 风格for..in对区间表达式调用toForStmt降级为普通for引入_xgo_k/_xgo_step/_xgo_end对含XGo_Enum的对象则通过cb.ForRange/cb.ForRangeEx生成迭代器调用。贯穿这三层的测试覆盖包括 cl/_testxgo/for-in、cl/_testxgo/rangeexpr、cl/_testxgo/for-phrase-basic、cl/_testxgo/for-range-basic、cl/_testxgo/for-range-int 以及 parser/_testdata/forloop读者可对照这些测试理解各形式for的实际行为与编译产物。总结XGo 的for语句用四个形态覆盖了从无限循环到逐值迭代的全部循环诉求裸for与条件for、C 风格for原样继承 Go 语义而for..in作为 XGo 原生迭代语法统一了整数、容器、区间表达式、迭代器函数与自定义类型XGo_Enum的遍历规则。理解for..in的绑定规则、if过滤语义与各类别的限制是在 XGo 中写出正确、高效、可维护迭代代码的关键也是为自己的类型接入 XGo 生态的第一步。赞分享编程语言编译器开发工具【免费下载链接】xgoXGo is a programming language that reads like plain English. But its also incredibly powerful — it lets you leverage assets from C/C, Go, Python, and JavaScript/TypeScript, creating a unified software engineering ecosystem. Our vision is to enable everyone to become a builder of the world.项目地址https://gitcode.com/gh_mirrors/go/xgo点击查看免费下载相关推荐uni-app UTS 可迭代协议Iterable全解析从 for..of 到 UTSValueIterable 自定义迭代uni app UTS 可迭代协议Iterable全解析从 for..of 到 UTSValueIterable 自定义迭代 UTS 是 uni app示例工程前端移动开发跨平台UTS 可迭代与可枚举协议深度解析for...of / for...in 跨端行为与 UTSValueIterable 自定义迭代实战UTS 可迭代与可枚举协议深度解析for...of / for...in 跨端行为与 UTSValueIterable 自定义迭代实战 本文基于 uni ap示例工程前端移动开发跨平台Rust By Practice 迭代器实战指南从 for 循环到自定义 IteratorRust By Practice 迭代器实战指南从 for 循环到自定义 Iterator 迭代器Iterator是 Rust 函数式编程的基石它把遍文档教程示例工程上一篇铜锁/Tongsuo API文档核心函数参数详解下一篇ElysiaGraphQLApollo Server与解析器创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考