for

SKILL.md

仓颉语言 for-in 迭代 Skill

1. for-in 基本语法

1.1 语法

for (item in sequence) {
    exprs
}
  • sequence 须实现 Iterable<T> 接口
  • sequence 表达式仅在首次迭代前求值一次
  • 循环表达式类型为 Unit,值为 ()

1.2 执行流程

  1. 求值 sequence,调用 iterator() 获取迭代器
  2. 调用迭代器 next():返回 None 则退出循环,返回 Some(value) 则继续
  3. value 绑定到 item,执行循环体
  4. 回到步骤 2

1.3 迭代变量规则

  • 迭代变量 item 不可变let 绑定),不能在循环体中重新赋值
  • 若循环体中不使用迭代变量,可用通配符 _ 占位避免警告:
    for (_ in 0..3) {
        println("hello")
    }
    

2. Range 区间类型

2.1 区间字面量

  • 半开区间(左闭右开):start..end — 不包含 end
  • 闭区间(左闭右闭):start..=end — 包含 end
  • 可选步长 : step,省略时默认为 1;step 不能为 0
for (i in 0..5) { print(i) }      // 输出:01234
for (i in 0..=5) { print(i) }     // 输出:012345
for (i in 0..10 : 2) { print(i) } // 输出:02468

2.2 逆向与步长

  • 负步长实现逆序迭代:
for (i in 5..0 : -1) { print(i) }  // 输出:54321
for (i in 10..0 : -3) { print(i) } // 输出:10741

2.3 空区间

  • step > 0 && start >= end(半开)或 step > 0 && start > end(闭)→ 空区间,循环体不执行
  • step < 0 && start <= end(半开)或 step < 0 && start < end(闭)→ 空区间

2.4 Range 类型签名

public struct Range<T> <: Iterable<T> where T <: Countable<T> & Comparable<T> & Equatable<T>
  • start: Tend: Tstep: Int64
  • isEmpty() 判断是否为空;iterator() 返回迭代器

3. Iterable 与 Iterator 接口

3.1 接口定义

interface Iterable<T> {
    func iterator(): Iterator<T>
}

interface Iterator<T> <: Iterable<T> {
    mut func next(): Option<T>
}
  • Iterator 自身扩展 Iterable,可直接用于 for-in
  • next() 返回 Some(value) 表示有元素,None 表示迭代结束

3.2 for-in 脱糖

for (i in list) { println(i) }

等价于:

var it = list.iterator()
while (let Some(i) <- it.next()) {
    println(i)
}

3.3 已实现 Iterable 的内置类型

类型 元素类型 有序
Range<T> T
Array<T> T
ArrayList<T> T
String Rune
HashMap<K, V> (K, V)
HashSet<T> T

4. 迭代进阶

4.1 元组解构

  • 对元素为元组的集合,可直接解构:
let points = [(1, 2), (3, 4), (5, 6)]
for ((x, y) in points) {
    println("x=${x}, y=${y}")
}
  • HashMap 迭代天然使用元组解构:
import std.collection.*

main() {
    let map = HashMap<String, Int64>([("a", 1), ("b", 2)])
    for ((key, value) in map) {
        println("${key}: ${value}")
    }
}

4.2 where 子句过滤

  • where 在循环体执行前过滤,比循环体内 if 更简洁:
// ✅ 推荐:where 过滤
for (i in 0..20 where i % 3 == 0) {
    println(i)  // 0, 3, 6, 9, 12, 15, 18
}

// ❌ 不推荐:循环体内 if 判断
for (i in 0..20) {
    if (i % 3 == 0) {
        println(i)
    }
}

4.3 break / continue

  • break 提前退出循环,continue 跳到下一次迭代
  • 二者类型均为 Nothing
for (i in 0..100) {
    if (i > 5) { break }
    if (i % 2 == 0) { continue }
    println(i)  // 1, 3, 5
}

4.4 String 迭代

注意 String 只实现了 Iterable<Byte>逐字节而不是逐字符迭代:

for (ch in "Hi仓颉") {
    println(ch)  // 逐个输出:72 105 228 187 147 233 162 137
}

如果需要逐字符(Rune)迭代,可以先调用 toRuneArray() 转为字符数组后再使用:

for (ch in "Hi仓颉".toRuneArray()) {
    println(ch)  // 逐个输出:H i 仓 颉
}

5. 自定义可迭代类型

实现 Iterable<T> 接口即可获得 for-in 支持:

class Countdown <: Iterable<Int64> {
    let start: Int64
    init(start: Int64) { this.start = start }

    public func iterator(): Iterator<Int64> {
        CountdownIterator(start)
    }
}

class CountdownIterator <: Iterator<Int64> {
    var current: Int64
    init(start: Int64) { current = start }

    public func next(): Option<Int64> {
        if (current > 0) {
            let v = current
            current--
            return Some(v)
        }
        return None
    }
}

main() {
    for (i in Countdown(5)) {
        print("${i} ")  // 输出:5 4 3 2 1
    }
}

6. 最优实践

6.1 优先使用 for-in

  • for-in 比手动 while + iterator() 更安全、简洁,且编译器可优化
  • 需要索引时可结合 enumerate()(若集合支持),否则使用 Range:
    let arr = [10, 20, 30]
    for (i in 0..arr.size) {
        println("arr[${i}] = ${arr[i]}")
    }
    

6.2 Range 计数循环

  • 固定次数循环优先用 Range,无需手动维护计数器:
    // ✅ 推荐
    for (_ in 0..n) { doSomething() }
    
    // ❌ 不推荐
    var i = 0
    while (i < n) { doSomething(); i++ }
    

6.3 where 替代 if

  • 过滤场景优先用 where 子句,减少嵌套、提升可读性(见 4.2)

6.4 注意无序集合

  • HashMapHashSet 迭代顺序不确定,不应依赖遍历顺序

6.5 常见错误

// ❌ 错误:试图修改迭代变量
for (i in 0..5) {
    // i = i + 1  // 编译错误,迭代变量不可变
}

// ❌ 错误:step 为 0
// for (i in 0..10 : 0) { }  // 运行时错误

// ❌ 错误:半开区间边界混淆
for (i in 0..5) { print(i) }   // 01234,不包含 5
for (i in 0..=5) { print(i) }  // 012345,包含 5
Weekly Installs
3
First Seen
3 days ago
Installed on
opencode2
gemini-cli2
claude-code2
github-copilot2
codex2
kimi-cli2