Dictionary 如何在Go中创建一流的映射迭代器?
我正在编写一个函数,它迭代映射中的条目。我希望能够在迭代时干净地处理从映射中添加或删除的项目,比如k的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
,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
}