我有一片reflect.Type
个值来定义函数的输入类型,我希望使用sync.Map
来缓存结果。
我意识到切片一般不能用作地图键,因此我搜索了一种从多个reflect.Type
值创建唯一键的方法。想法包括
reflect.Type.String()
的串联。 godoc明确表示不要将它用于平等,因此密钥不会是唯一的。fmt.Sprintf("%#v", subKey)
的串联 - 请参阅here。我不知道这些密钥是否是唯一的。sync.Map
创建一个树[深度len(切片)]的地图映射...其中值的查找涉及遍历每个子项的地图树中的更深层。这似乎很慢而且很麻烦,但应该有效。why slices can't be used as keys上的引用表明如何定义切片上的相等性可能不清楚。在这种情况下,当且仅当切片具有相同的长度时,我才希望元素相等。
找到reflect.Type
的字节表示类似于类似问题here的解决方案,真是太棒了。
答案 0 :(得分:0)
根据评论中的建议,我使用hashing-reflect-type解决方案实现了一个解决方案,但适用于任何类型的哈希类型。
import (
"reflect"
"strconv"
"strings"
"sync"
)
// IdHashmap stores the next id as an int64 and a map pointing to the
// unique id for each hashable key
type IdHashmap struct {
nextId int64
hashMap map[interface{}]string
mutex sync.Mutex
}
// LoadOrStore returns the existing value for the key if present.
// Otherwise, it stores and returns the given value.
// The loaded result is true if the value was loaded, false if stored.
// The value is an a unique id for the object that was passed (or
// object reference). It is a stringified int64
// representing the number of unique objects passed to this IdHashmap
// before this object was first passed in
func (hm *IdHashmap) LoadOrStore(subKey interface{}) (hashmapId string) {
if hm.hashMap == nil {
hm.hashMap = make(map[interface{}]string)
}
// the entry for a given key is only ever written once but read many times
if id, ok := hm.hashMap[subKey]; ok {
return id
}
hm.mutex.Lock()
// check for the possibility that someone else wrote a value for
// this subKey while this thread waited for the lock
if id, ok := hm.hashMap[subKey]; ok {
return id
}
id := strconv.FormatInt(hm.nextId, 10)
hm.nextId++
hm.hashMap[subKey] = id
hm.mutex.Unlock()
return id
}
// LoadOrStoreForSlice gets a unique id for a given slice of objects
// by concatenating hashmapids of its elements
func (hm *IdHashmap) LoadOrStoreForSlice(keys interface{}) (hashmapId string) {
if reflect.TypeOf(keys).Kind() == reflect.Slice {
s := reflect.ValueOf(keys)
ids := make([]string, s.Len())
for i := 0; i < s.Len(); i++ {
ids[i], _ = hm.LoadOrStore(s.Index(i))
}
return strings.Join(ids, ",")
}
// if not a slice try hashing directly in case the type is hashable
id, _ := hm.LoadOrStore(keys)
return id
}