go1.18beta1 泛型demo: hashmap
Posted yzbmz5913
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go1.18beta1 泛型demo: hashmap相关的知识,希望对你有一定的参考价值。
go终于出泛型了,整个烂活玩玩,体验一下,总体感觉还是有点别扭,主要有两处不完善
// hashmap.go package hashmap import ( "bytes" "encoding/gob" "fmt" "hash/fnv" "reflect" ) type HashMap[K comparable, V any] struct table []*entry sz int type entry struct key any value any next *entry func NewHashMap[K comparable, V any](cap int) *HashMap[K, V] cap = powOfTwo(cap) table := make([]*entry, cap, cap) return &HashMap[K, V]table: table const MaxCap = 1 << 30 func powOfTwo(cap int) int n := cap - 1 n |= n >> 1 n |= n >> 2 n |= n >> 4 n |= n >> 8 n |= n >> 16 if n < 0 return 1 if n >= MaxCap return MaxCap return n + 1 func (m *HashMap[K, V]) Put(key K, value V) factor := float32(m.sz) / float32(len(m.table)) if factor > 0.75 m.resize() h := m.hash(key) idx := h & (uint64(len(m.table) - 1)) e := m.table[idx] for e != nil if reflect.DeepEqual(e.key, key) e.value = value return e = e.next n := &entrykey: key, value: value n.next = m.table[idx] m.table[idx] = n m.sz++ func (m *HashMap[K, V]) Get(key K) (v V, ok bool) h := m.hash(key) idx := h & (uint64(len(m.table) - 1)) e := m.table[idx] for e != nil if reflect.DeepEqual(e.key, key) return e.value.(V), true e = e.next return func (m *HashMap[K, V]) Remove(key K) (v V, ok bool) defer func() if ok m.sz-- () h := m.hash(key) idx := h & (uint64(len(m.table) - 1)) e := m.table[idx] if reflect.DeepEqual(e.key, key) m.table[idx] = m.table[idx].next return e.value.(V), true for e.next != nil if reflect.DeepEqual(e.next.key, key) v = e.next.value.(V) e.next = e.next.next return v, true e = e.next return func (m *HashMap[K, V]) Size() int return m.sz func (m *HashMap[K, V]) Foreach(f func(key K, value V)) for _, e := range m.table if e == nil continue for e != nil f(e.key.(K), e.value.(V)) e = e.next func (m *HashMap[K, V]) resize() newC := uint64(len(m.table)) << 1 newTable := make([]*entry, newC, newC) m.Foreach(func(key K, value V) h := m.hash(key) idx := h & (newC - 1) n := &entrykey: key, value: value n.next = newTable[idx] newTable[idx] = n ) m.table = newTable func (m *HashMap[K, V]) hash(obj K) uint64 b := bytes.Buffer _ = gob.NewEncoder(&b).Encode(obj) h := fnv.New64a() _, _ = h.Write(b.Bytes()) return h.Sum64() func (m *HashMap[K, V]) String() string buf := bytes.NewBufferString("[") i := 0 m.Foreach(func(key K, value V) buf.WriteString(fmt.Sprintf("<%v,%v>", key, value)) if i != m.sz-1 buf.WriteByte(\',\') i++ ) buf.WriteRune(\']\') return buf.String()
测试代码:
// main.go package main import ( "./hashmap" "fmt" ) func main() m := hashmap.NewHashMap[string, int](3) m.Put("stan", 1) m.Put("kyle", 2) m.Put("kenny", 3) m.Put("eric", 4) m.Put("butters", 5) m.Put("craig", 6) m.Put("clyde", 7) m.Put("jimmy", 8) m.Put("token", 9) m.Remove("eric") m.Remove("butters") fmt.Println(m.Get("stan")) fmt.Println(m.Get("kyle")) fmt.Println(m.Get("kenny")) fmt.Println(m.Get("eric")) fmt.Println(m.Get("butters")) fmt.Println(m.Get("craig")) fmt.Println(m.Get("clyde")) fmt.Println(m.Get("jimmy")) fmt.Println(m.Get("token")) fmt.Println("-----------------------------") fmt.Println(m)
基本使用确实没什么问题,但是有两处地方有点别扭
1. hashmap.go第56行、73行等处必须使用reflect.DeepEqual(e.key, key)而不是直接e.key == key。
难道==的语义不该看运行时类型吗?目前的处理方式貌似是因为是泛型参数,一律以iface看待,==也就会比较Value,显然不相等(因为Value.ptr不相等)
2. 不支持嵌套类型(也就是所谓内部类),导致entry的定义只能是
type entry struct key any value any next *entry
而不是
type entry[K comparable, V any] struct key K value V next *entry[K, V]
因为后者的泛型参数K和HashMap的泛型参数K用的是两个命名空间,不能互相赋值。。。所以只能用any类型占位,赋值时再强转成HashMap的泛型类型K、V,十分别扭。
希望后续版本中能够改进。
以上是关于go1.18beta1 泛型demo: hashmap的主要内容,如果未能解决你的问题,请参考以下文章