仓颉探索-实现自己的迭代器

359 阅读2分钟

迭代器工作原理

具体的细节可以看官方文档

迭代器原理

其中使用到两个数据结构

Iterable

image.png

Iterator

该类是一个泛型基类,所以可以完成任意数据的迭代

其中最重要的是next方法,迭代过程中会返回Some值,迭代到末尾会返回None。

image.png

for in 工作原理

通常我们会使用如下的代码遍历数组集合。这里面其实就使用到了迭代器

let list = [1, 2, 3]
for (i in list) {
    println(i)
}

它等价于以下代码

  1. Array 遵循接口 Iterable,我们通过iterator获取ArrayIterator迭代器
  2. 在while循环内,不断地调用next方法取值
  3. 取到最后返回None,结束while循环
let list = [1, 2, 3]
var it = list.iterator()
while (true) {
    match (it.next()) {
        case Some(i) => println(i)
        case None => break
    }
}

不过我更倾向于while let语法进行遍历

原理和上面的过程一样,只不过代码更简洁,在取值的过程中使用了模式匹配

模式匹配

let list = [1, 2, 3]
var it = list.iterator()
while (let Some(i) <- it.next()) {
    println(i)
}

自定义迭代器

  1. 自定义类MyClass遵守接口Iterable,返回一个自定义迭代器MyIterator
  2. 自定义MyIterator遵守接口Iterator,实现next方法并在内部维护迭代的下标
import std.collection.{ArrayList, HashSet, HashMap}
// 一个迭代器,内部维护迭代的次数,保存需要迭代的数据
class MyIteratorClass<T> <: Iterator<T> {
    var index: Int = 0
    private let dataList: Array<T>
    init(dataList: Array<T>) {
        this.dataList = dataList
    }

    public func next(): Option<T> {
        let v = dataList.get(index)
        index += 1
        return v
    }
}

// 自定义可迭代的类
class MyIterableClass<T> <: Iterable<T> {
    let list: Array<T>
    let name: String = 'MyIterableClass'
    init(list: Array<T>) {
        this.list = list
    }
    // 需要返回一个迭代器用来迭代数据
    // 这里迭代的数据是this.list
    public func iterator(): Iterator<T> {
        MyIteratorClass(this.list)
    }
}

func demo() {
    let list = Array(80) {i => i}
    let myCls = MyIterableClass(list)
    // 迭代器赋值
    let a: Iterable<Int64> = myCls
    for (i in myCls) {
        println('for-in myCls ${i}')
    }
}