在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语言不直接提供枚举器或者枚举的方法呢?