如何在 Go 中创建一流的地图迭代器?

cpc*_*len 6 dictionary iterator go

我正在编写一个迭代映射中的条目的函数。我希望能够干净地处理迭代时从地图中添加或删除的项目,就像for k, v := range myMap { //...所做的那样,但我每次迭代只处理一个键/值对,所以我不能使用范围。我想要这样的东西:

func processItem(i iterator) bool {
     k, v, ok := i.next()
     if(!ok) {
         return false
     }
     process(v)
     return true
}

var m = make(map[string]widget)
// ...
i := makeIterator(m)
for processItem(i) {
    // code which might add/remove item from m here
}
Run Code Online (Sandbox Code Playgroud)

我知道 range 使用 ' hiter' 结构体和关联函数(如 中定义src/runtime/hashmap.go)来执行迭代。有没有什么方法可以访问这个迭代器作为一个具体化的(一流的)Go 对象?

是否有另一种迭代映射的策略可以很好地处理插入/删除,但提供一流的迭代器对象?

额外问题:是否有另一种迭代映射的策略,该策略可以处理映射和迭代器被序列化到磁盘然后恢复的情况,迭代从停止的地方继续?(显然内置迭代range器不具备这个能力!)

cd1*_*cd1 6

你不能:(

迭代 a 的唯一方法map是使用for range,并且您无法从中获取迭代器对象。


nem*_*emo 5

您可以使用通道作为迭代器。

您的迭代器将是一个返回通道的函数,该通道将当前迭代值传达给接收它的人:

func iterator(m map[string]widget) chan iteration {
    c := make(chan iteration)
    go func() {
        for k,v := range m {
            c <- iteration{k,v}
        }
        close(c)
    }()
    return c
}
Run Code Online (Sandbox Code Playgroud)

这当然不是通用的,您可以使用interface{}和/或反射使其通用,但如果您确实需要它,那应该不会太难。在迭代结束时关闭通道将通知迭代结束,稍后演示。

类型iteration就在那里,因此您可以同时发送键和值,它看起来像这样:

type iteration struct {
    key string
    value widget
}
Run Code Online (Sandbox Code Playgroud)

有了这个,你就可以这样做(在游戏中):

m := map[string]widget{"foo": widget{3}, "bar": widget{4}}
i := iterator(m)

iter, ok := <- i
fmt.Println(iter, ok)
iter, ok = <- i
fmt.Println(iter, ok)
iter, ok = <- i
fmt.Println(iter, ok)
Run Code Online (Sandbox Code Playgroud)

这产生

{foo {3}} true
{bar {4}} true
{ {0}} false
Run Code Online (Sandbox Code Playgroud)