Dictionary 如何在Go中创建一流的映射迭代器?

Dictionary 如何在Go中创建一流的映射迭代器?,dictionary,go,iterator,Dictionary,Go,Iterator,我正在编写一个函数,它迭代映射中的条目。我希望能够在迭代时干净地处理从映射中添加或删除的项目,比如k的,v:=range myMap{//…,但我每次迭代只处理一个键/值对,所以我不能使用range。我希望类似这样的东西: func processItem(i iterator) bool { k, v, ok := i.next() if(!ok) { return false } process(v) return true

我正在编写一个函数,它迭代映射中的条目。我希望能够在迭代时干净地处理从映射中添加或删除的项目,比如k的
,v:=range myMap{//…
,但我每次迭代只处理一个键/值对,所以我不能使用range。我希望类似这样的东西:

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
}
我知道range正在使用“
hiter
”结构和相关函数(如
src/runtime/hashmap.go
中所定义)来执行迭代。是否有某种方法可以将此迭代器作为具体化(一级)go对象访问

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

附加问题:是否有一种迭代映射的替代策略,该策略还可以处理映射和迭代器被序列化到磁盘,然后恢复,迭代从停止的地方继续进行?(显然内置的
范围
迭代器没有此功能!)

您不能:(


迭代
映射的唯一方法是使用
for range
,您无法从中获取迭代器对象。

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

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

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
}
有了这个,您就可以这样做():


您可以定义自己的映射类型。这也有助于解决并发问题:

type ConcurrentMap struct {
    sync.RWMutex
    items map[string]interface{}
}

type ConcurrentMapItem struct {
    Key   string
    Value interface{}
}

func (cm *ConcurrentMap) Iter() <-chan ConcurrentMapItem {
    c := make(chan ConcurrentMapItem)

    f := func() {
        cm.Lock()
        defer cm.Unlock()

        for k, v := range cm.items {
            c <- ConcurrentMapItem{k, v}
        }
        close(c)
    }
    go f()

    return c
}
输入ConcurrentMap结构{
sync.RWMutex
项映射[字符串]接口{}
}
类型ConcurrentMapItem结构{
键串
值接口{}
}

func(cm*ConcurrentMap)Iter()一种非常简单的方法是获取映射中所有键的列表,并将列表和映射打包到迭代器结构中。当我们需要下一个键时,我们从映射中未删除的列表中获取下一个键:

type iterator struct {
    m    map[string]widget
    keys []string
}

func newIterator(m map[string]widget) *iterator {
    it := iterator{m, make([]string, len(m))}
    i := 0
    for k, _ := range m {
        it.keys[i] = k
        i++
    }
    return &it
}

func (it *iterator) next() (string, widget, bool) {
    for len(it.keys) > 0 {
        k := it.keys[0]
        it.keys = it.keys[1:]
        if _, exists := it.m[k]; exists {
            return k, it.m[k], true
        }
    }
    return "", widget{0}, false
}

我不明白您想做什么。在对映射进行迭代的同时更改映射中的值是完全有效的。您是不是特别希望有一个数据结构可以恢复部分迭代的映射?正确:我希望有一个数据结构可以让我恢复部分复杂的映射ted映射迭代。查看了range语句的go源代码。这是一个很难理解的代码,但从我所知,可能可以将另一个关键字
from
编码到语言中。它本身不是一个迭代器,但给定
m map[string]接口{}
,您可以对k执行
,v:=range m from“hello”{
。当然,对于任何类型的键。也可以用于切片,
…来自42{}
从索引42开始。当然你可以在一个切片上进行自己的迭代,但范围有点好。别提那条评论。我会把它留给可能的讨论,但考虑到地图的性质,它们的迭代器在基本层面上没有意义。至少没有足够的意义在语言中添加关键字。我喜欢这个。它,我有点担心它可能会违反hashmap的内部检查。go会尝试检测来自不同Goroutine的对映射的并发访问。啊,是的,我忘记了修改部分,抱歉。在这种情况下,您可能必须在迭代器中对修改进行建模,然后它看起来会比这不好。同步互斥锁将防止由于并发映射访问而导致的恐慌,但它(如果使用正确)也将防止在对映射进行迭代时对其进行修改。我需要能够在迭代时修改映射。这对于普通映射非常有效(前提是迭代和修改在同一个goroutine中完成)。
{foo {3}} true
{bar {4}} true
{ {0}} false
type ConcurrentMap struct {
    sync.RWMutex
    items map[string]interface{}
}

type ConcurrentMapItem struct {
    Key   string
    Value interface{}
}

func (cm *ConcurrentMap) Iter() <-chan ConcurrentMapItem {
    c := make(chan ConcurrentMapItem)

    f := func() {
        cm.Lock()
        defer cm.Unlock()

        for k, v := range cm.items {
            c <- ConcurrentMapItem{k, v}
        }
        close(c)
    }
    go f()

    return c
}
type iterator struct {
    m    map[string]widget
    keys []string
}

func newIterator(m map[string]widget) *iterator {
    it := iterator{m, make([]string, len(m))}
    i := 0
    for k, _ := range m {
        it.keys[i] = k
        i++
    }
    return &it
}

func (it *iterator) next() (string, widget, bool) {
    for len(it.keys) > 0 {
        k := it.keys[0]
        it.keys = it.keys[1:]
        if _, exists := it.m[k]; exists {
            return k, it.m[k], true
        }
    }
    return "", widget{0}, false
}