在golang-nuts上看到有人问怎么样去枚举一个map。在go语言层面,并不支持支持枚举map,也就是说你不能获得一个枚举器在任意时刻去枚举这个map,只能用range一次性地遍历这个map。但是我们可以用map+list的方式来实现一个可以枚举的map。请看代码:

import (

"container/list"
"fmt"
)
type Iterator struct {

e *list.Element
}
func (p *Iterator) Valid() bool {

return p.e != nil
}
func (p *Iterator) Value() (int, int) {

pe := p.e.Value.(*Element)

return pe.k, pe.v
}
func (p *Iterator) Next() {

p.e = p.e.Next()
}
type Element struct {

k, v int
}
type ListMap struct {

m map[int]*list.Element
l *list.List
}
func NewListMap() *ListMap {

return &ListMap{


m: make(map[int]*list.Element),

l: list.New(),

}
}
func (p *ListMap) Set(k, v int) {

e, ok := p.m[k]
if ok {


e.Value.(*Element).v = v

} else {


p.m[k] = p.l.PushBack(&Element{k, v})

}
}
func (p *ListMap) Remove(k int) {

e, ok := p.m[k]
if ok {


delete(p.m, k)

p.l.Remove(e)

}
}
func (p *ListMap) Get(k int) (int, bool) {

e, ok := p.m[k]
if !ok {


return 0, false

}
return e.Value.(*Element).v, true
}
func (p *ListMap) Iterate() Iterator {

return Iterator{p.l.Front()}
}

使用的例子:

func main() {


m := NewListMap()

m.Set(1, 1)

m.Set(2, 2)

m.Set(3, 3)

m.Set(3, 300)

m.Remove(2)

it := m.Iterate()

for it.Valid() {



fmt.Println(it.Value())


it.Next()


}

}

输出:

1 1

3 300

说明:

为了达到更好的通用性,可以把key和value的类型都换成interface{}类型,但是会稍微损失一些性能。

一个思考题:

为什么go语言不直接提供枚举器或者枚举的方法呢?