本文共 6607 字,大约阅读时间需要 22 分钟。
数据结构设计 数据字典
A dictionary stores [key, value]
pairs. Go provides a very convenient implementation of a dictionary by its built-in map
type.
字典存储[key, value]
对。 Go通过其内置的map
类型为字典提供了非常方便的实现。
In this article I’ll enrich the map
built-in type with some convenient operations to get information out of it, and to change its content.
在本文中,我将通过一些方便的操作来丰富map
内置类型,以从中获取信息并更改其内容。
I’ll create a ItemDictionary
generic type, concurrency safe, that can generate dictionaries for any type. By running genny
the code will create a type-specific Dictionary implementation, encapsulating the actual map
containing the data.
我将创建一个并发安全的ItemDictionary
泛型类型,该泛型可以为任何类型生成字典。 通过运行genny
,代码将创建特定于类型的Dictionary实现,封装包含数据的实际map
。
The dictionary is created using dict := ValueDictionary{}
and provides this set of exported methods:
该字典是使用dict := ValueDictionary{}
创建的,并提供了以下导出方法集:
Set()
Set()
Delete()
Delete()
Has()
Has()
Get()
Get()
Clear()
Clear()
Size()
Size()
Keys()
Keys()
Values()
Values()
// Package dictionary creates a ValueDictionary data structure for the Item typepackage dictionaryimport ( "sync" "github.com/cheekybits/genny/generic")// Key the key of the dictionarytype Key generic.Type// Value the content of the dictionarytype Value generic.Type// ValueDictionary the set of Itemstype ValueDictionary struct { items map[Key]Value lock sync.RWMutex}// Set adds a new item to the dictionaryfunc (d *ValueDictionary) Set(k Key, v Value) { d.lock.Lock() defer d.lock.Unlock() if d.items == nil { d.items = make(map[Key]Value) } d.items[k] = v}// Delete removes a value from the dictionary, given its keyfunc (d *ValueDictionary) Delete(k Key) bool { d.lock.Lock() defer d.lock.Unlock() _, ok := d.items[k] if ok { delete(d.items, k) } return ok}// Has returns true if the key exists in the dictionaryfunc (d *ValueDictionary) Has(k Key) bool { d.lock.RLock() defer d.lock.RUnlock() _, ok := d.items[k] return ok}// Get returns the value associated with the keyfunc (d *ValueDictionary) Get(k Key) Value { d.lock.RLock() defer d.lock.RUnlock() return d.items[k]}// Clear removes all the items from the dictionaryfunc (d *ValueDictionary) Clear() { d.lock.Lock() defer d.lock.Unlock() d.items = make(map[Key]Value)}// Size returns the amount of elements in the dictionaryfunc (d *ValueDictionary) Size() int { d.lock.RLock() defer d.lock.RUnlock() return len(d.items)}// Keys returns a slice of all the keys presentfunc (d *ValueDictionary) Keys() []Key { d.lock.RLock() defer d.lock.RUnlock() keys := []Key{} for i := range d.items { keys = append(keys, i) } return keys}// Values returns a slice of all the values presentfunc (d *ValueDictionary) Values() []Value { d.lock.RLock() defer d.lock.RUnlock() values := []Value{} for i := range d.items { values = append(values, d.items[i]) } return values}
The tests describe the usage of the above implementation. Notice that we never interact with the underlying map
type, which might as well be implemented in another way if only Go didn’t provide us a map type already.
这些测试描述了上述实现的用法。 请注意,我们从不与基础map
类型进行交互,如果仅Go尚未为我们提供map
类型,则也可以通过其他方式实现。
package dictionaryimport ( "fmt" "testing")func populateDictionary(count int, start int) *ValueDictionary { dict := ValueDictionary{} for i := start; i < (start + count); i++ { dict.Set(fmt.Sprintf("key%d", i), fmt.Sprintf("value%d", i)) } return &dict}func TestSet(t *testing.T) { dict := populateDictionary(3, 0) if size := dict.Size(); size != 3 { t.Errorf("wrong count, expected 3 and got %d", size) } dict.Set("key1", "value1") //should not add a new one, just change the existing one if size := dict.Size(); size != 3 { t.Errorf("wrong count, expected 3 and got %d", size) } dict.Set("key4", "value4") //should add it if size := dict.Size(); size != 4 { t.Errorf("wrong count, expected 4 and got %d", size) }}func TestDelete(t *testing.T) { dict := populateDictionary(3, 0) dict.Delete("key2") if size := dict.Size(); size != 2 { t.Errorf("wrong count, expected 2 and got %d", size) }}func TestClear(t *testing.T) { dict := populateDictionary(3, 0) dict.Clear() if size := dict.Size(); size != 0 { t.Errorf("wrong count, expected 0 and got %d", size) }}func TestHas(t *testing.T) { dict := populateDictionary(3, 0) has := dict.Has("key2") if !has { t.Errorf("expected key2 to be there") } dict.Delete("key2") has = dict.Has("key2") if has { t.Errorf("expected key2 to be removed") } dict.Delete("key1") has = dict.Has("key1") if has { t.Errorf("expected key1 to be removed") }}func TestKeys(t *testing.T) { dict := populateDictionary(3, 0) items := dict.Keys() if len(items) != 3 { t.Errorf("wrong count, expected 3 and got %d", len(items)) } dict = populateDictionary(520, 0) items = dict.Keys() if len(items) != 520 { t.Errorf("wrong count, expected 520 and got %d", len(items)) }}func TestValues(t *testing.T) { dict := populateDictionary(3, 0) items := dict.Values() if len(items) != 3 { t.Errorf("wrong count, expected 3 and got %d", len(items)) } dict = populateDictionary(520, 0) items = dict.Values() if len(items) != 520 { t.Errorf("wrong count, expected 520 and got %d", len(items)) }}func TestSize(t *testing.T) { dict := populateDictionary(3, 0) items := dict.Values() if len(items) != dict.Size() { t.Errorf("wrong count, expected %d and got %d", dict.Size(), len(items)) } dict = populateDictionary(0, 0) items = dict.Values() if len(items) != dict.Size() { t.Errorf("wrong count, expected %d and got %d", dict.Size(), len(items)) } dict = populateDictionary(10000, 0) items = dict.Values() if len(items) != dict.Size() { t.Errorf("wrong count, expected %d and got %d", dict.Size(), len(items)) }}
You can use this generic implemenation to generate type-specific dictionaries, using
您可以使用以下通用实现来生成特定于类型的字典,方法是:
//generate a `IntDictionary` dictionary of `string` keys associated to `int` valuesgenny -in dictionary.go -out dictionary-string-int.go gen "Key=string Value=int"//generate a `StringDictionary` dictionary of `string` keys associated to `string` valuesgenny -in dictionary.go -out dictionary-string-string.go gen "Key=string Value=string"
翻译自:
数据结构设计 数据字典
转载地址:http://bhqgb.baihongyu.com/