# for 循环 ## 功能 `for` 用于重复执行代码、按整数区间循环、无限循环,也用于遍历数组、对象和字符串。 数组按下标和值遍历,对象按 key 和 value 遍历,字符串按字符遍历。整数次数和区间循环使用惰性迭代状态,不会提前生成完整数组。 ## 语法 ```bt // 无限循环 for { statement } // 重复 count 次 for count { statement } // 重复 count 次,i 为下标 for i in count { statement } // 重复 count 次,i 从 0 开始按 step_value 递增 for i in count step step_value { statement } // 从 start 到 end,i 为下标 for i in start..end { statement } // 从 0 到 end,i 为下标 for i in ..end { statement } // 从 start 开始无限递增,i 为下标 for i in start.. { statement } // 正反向步长 for i in start..end step step_value { statement } // 遍历可迭代对象 for value in iterable { value } // 遍历对象 for key, value in iterable { value } // 逗号可省略 for key value in iterable { value } // _ 占位 for _, value in iterable { value } // 解构赋值 for (name, age) in iterable { name } // 标签循环,主要用于多 for 嵌套循环 for:label key, value in iterable { break:label } ``` ## 参数 | 参数 | 类型 | 必填 | 说明 | |---|---|---|---| | count | Int | 是 | 循环次数,必须是非负整数。 | | start | Int | 否 | 区间起点,省略时默认为 `0`。 | | end | Int | 否 | 闭区间终点,省略时表示从 `start` 开始无限递增。 | | step_value | Int | 否 | 正整数步长,默认 `1`;用于次数循环时控制当前值增量,用于区间循环时控制区间步幅。 | | iterable | Array/Object/String/Int | 是 | 可遍历值;整数会按 `0..count - 1` 惰性循环。 | | key | String/Int | 否 | 数组和字符串为下标,对象为 key,整数次数循环为当前整数,区间为零基序号。 | | value | Any | 否 | 当前元素值;区间和整数次数循环中为当前整数。 | | _ | Empty | 否 | 占位索引变量 | ## 返回值 `for` 语句本身返回 `empty`。如果需要收集结果,通常先创建数组或对象,在循环体内写入。 ## 无限循环 `for {}` 表示无限循环,需要在循环体内通过 `break`、`return` 或 `exit` 退出。 ```bt i = 0 for { if i >= 3 { break } println i i += 1 } ``` ## 重复 N 次 不需要索引时,直接写次数。 ```bt for 3 { println 'hello' } ``` 需要索引时,使用 `for i in count`。索引从 `0` 开始,到 `count - 1` 结束。 ```bt for i in 3 { println i } ``` 需要固定循环次数但让变量按指定步长递增时,使用 `for i in count step step_value`。下面会循环 3 次,输出 `0`、`2`、`4`。 ```bt for i in 3 step 2 { println i } ``` ## 区间循环 `start..end` 是闭区间,包含左右边界。起点小于等于终点时递增,起点大于终点时递减。 ```bt for i in 1..3 { println i } for i in 3..1 { println i } ``` `..end` 等价于 `0..end`。 ```bt for i in ..3 { println i } ``` `start..` 表示从起点开始无限递增。 ```bt for i in 100.. { if i > 102 { break } println i } ``` ## step `step` 用于控制 `for` 循环中每次迭代的变量变动幅度(步长)。次数循环会固定执行 `count` 次,变量从 `0` 开始每轮增加 `step`;区间循环的方向由区间起始值与结束值的大小关系自动决定。 ### 语法 `for <变量> in <次数> step <步长>` `for <变量> in <区间> step <步长>` ## 约束条件 - `step` 必须为 **大于 `0` 的整数** - 不支持负值步长(方向由区间自动决定) ## 行为规则 ### 1. 默认步长 当省略 `step` 时,步长默认为 `1`。 ### 2. 次数循环 `for i in count step step_value` 会执行 `count` 次,`i` 依次为 `0`、`step_value`、`step_value * 2`,直到达到执行次数,不会把 `count` 当作闭区间终点。 ### 3. 方向自动判定 - **正向迭代**:当 `起始 ≤ 结束` 时,每次循环变量 **增加** `step` - **反向迭代**:当 `起始 > 结束` 时,每次循环变量 **减少** `step` ### 4. 区间特性 - 区间为 **闭区间**:起始值和结束值均会被迭代(若步长能精确到达) - 正向迭代终止条件:`变量 > 结束` - 反向迭代终止条件:`变量 < 结束` ### 示例 | 代码 | 迭代序列 | 说明 | |------|----------|------| | `for i in 3 step 2` | 0, 2, 4 | 循环 3 次,当前值按 2 递增 | | `for i in 0..6` | 0, 1, 2, 3, 4, 5, 6 | 默认步长 1,正向 | | `for i in 0..6 step 2` | 0, 2, 4, 6 | 步长 2,正向 | | `for i in 6..0` | 6, 5, 4, 3, 2, 1, 0 | 默认步长 1,反向 | | `for i in 6..0 step 2` | 6, 4, 2, 0 | 步长 2,反向 | | `for i in 1..10 step 3` | 1, 4, 7, 10 | 步长 3,正向 | | `for i in 10..1 step 3` | 10, 7, 4, 1 | 步长 3,反向 | ```bt for i in 3 step 2 { // 0, 2, 4 println i } for i in 0..6 step 2 { // 0, 2, 4, 6 println i } for i in 6..0 step 2 { // 6, 4, 2, 0 println i } ``` ### 设计原理 `step` 仅定义每次迭代的变动幅度(步长绝对值)。区间循环的迭代方向完全由起始与结束的大小关系隐式决定,避免了显式指定 `-2` 这类负步长的冗余。 ## 遍历集合 只关心元素本身时,写一个变量即可。 ```bt names = ['Lisa', 'Suci', 'Emerie'] for name in names { println name } ``` 需要下标或对象 key 时,写两个变量:第一个是 key,第二个是 value。两个变量之间的逗号可写可省略。 ```bt users = {name: 'Lisa', age: 18} for key, value in users { println key + ': ' + string(value) } for key value in users { println key + ': ' + string(value) } ``` ## 丢弃绑定 `_` 表示丢弃当前绑定,不会创建或覆盖名为 `_` 的变量。 ```bt for _, value in users { println value } for key, _ in users { println key } for _, _ in users { println 'item' } ``` ## 解构当前 value 当遍历数组中的对象或数组时,可以在 `for` 后使用括号解构当前 value,只取循环体需要的字段。 ```bt users = [ {name: '张三', age: 18} {name: '李四', age: 20} ] for (name age) in users { println name + ':' + string(age) } ``` 上面的写法等价于: ```bt for index, user in users { name = user.name age = user.age println name + ':' + string(age) } ``` 括号内可以使用空格或逗号分隔变量。当前 value 是 object 时按同名字段读取,是 array 时按下标读取;缺失字段或下标赋值为 `empty`。当前 value 不是 array 或 object 时会产生运行时错误。 ## break 和 continue `break` 立即结束当前循环;`continue` 跳过本次循环剩余语句,进入下一次循环。 ```bt for index, value in [1, 2, 3, 4] { if value == 2 { continue } if value == 4 { break } println value } ``` ## 标签循环 嵌套循环中,可以给循环加标签,然后用 `break:label` 或 `continue:label` 控制指定层级。冒号用于明确表示后面是跳转标签,标签写在循环关键字后面,格式为 `for:a`、`while:a` 或 `loop:a`。 ```bt arr = ['Lisa', 'Suci', 'Emerie'] list = ['Rita', 'maria', 'Jenna'] for:a k1, v1 in arr { for:b k2, v2 in list { if k1 == 1 { break:a } if k2 == 1 { continue:b } println v2 } println v1 } ``` ## 注意事项 - `for count {}` 的 count 必须是非负整数;`0` 会执行零次。 - `for i in count {}` 中的 count 为整数时,按 `0..count - 1` 循环;`for i in count step step_value {}` 会循环 count 次,i 从 `0` 开始按 step_value 递增。 - 区间循环只支持整数,第一版不支持浮点 step。 - `start..end` 包含 end。 - `start..` 是无限递增区间,通常需要在循环体内配合 `break`。 - `for value in obj` 仍然读取对象 value;需要对象 key 时使用 `for key, value in obj` 或 `for key value in obj`。