我正在尝试为Google DataStore编写Go自定义缓存(更确切地说,是对现有缓存库之一的包装)。在缓存初始化时,它应该接受任何自定义类型的结构(带有适当定义的数据存储区),然后这将成为存储所有项目的基础。这个想法是,可以针对各种类型创建/初始化缓存,以反映特定数据存储条目( CustomEntry )
的结构。方法1 -存储 reflect.Type 并使用它。 遇到的问题-无法遍历自定义类型的切片
type CustomEntry struct {
Data struct {
name string `datastore:"name,noindex"`
address []string `datastore:"address,noindex"`
} `datastore:"data,noindex"`
}
func (cache *MyCache) CacheData(dataQuery string, dataType reflect.Type) {
slice := reflect.MakeSlice(reflect.SliceOf(dataType), 10, 10)
if keys, err := DataStoreClient.GetAll(cache.ctx, datastore.NewQuery(dataQuery), &slice); err != nil {
//handle error
} else {
for i, dataEntry:= range slice {
// ERROR: Cannot range over 'slice' (type Value)
cache.Set(keys[i].Name, dataEntry)
}
}
//usage: Cache.CacheData("Person", reflect.TypeOf(CustomEntry{})
方法2 -接受一组接口作为参数。 遇到的问题 = [] CustomEntry 不是 []界面{}
func (cache *MyCache) CacheData(dataQuery string, dataType []interface{}) {
if keys, err := DataStoreClient.GetAll(cache.ctx, datastore.NewQuery(dataQuery), &dataType); err != nil {
//handle error
} else {
for i, dataEntry:= range slice {
// this seems to work fine
cache.Set(keys[i].Name, dataEntry)
}
}
//usage:
var dataType []CustomEntry
Cache.CacheData("Person", data)
// ERROR: Cannot use 'data' (type []CustomEntry) as type []interface{}
任何建议将不胜感激。
答案 0 :(得分:0)
我找到了一个解决方案,并认为如果其他任何人遇到类似的问题,也值得分享。
最简单的方法是启动DataStore希望接收的结构切片,然后将指向它的指针作为参数(接口{})传递到所需的函数中。与一些取消封送功能(我曾尝试过使用JSON包)类似,DataStore能够成功将数据追加到其中。
在给定特定类型的情况下,尝试在函数中动态创建切片,然后该切片将被函数(例如DataStore客户端)接受,这可能非常困难(我还没有设法找到一种方法)。同样,传递一片接口(以便进行简单的迭代)只会使事情复杂化。
第二,为了遍历数据(例如,将其存储在缓存中),必须:
(1)检索接口的基础值(即指针本身)-可以使用reflect.ValueOf(pointerInterface)
来实现,
(2)取消引用指针,以便我们可以访问底层的可迭代结构片段-可以通过调用.Elem()
来实现,
(3)使用.Index(i)
方法在基础切片上进行迭代(即使基础类型是可迭代的,range
也不会接受接口)。
自然地,添加一些switch-case语句可能适合于确保捕获任何错误而不是引起运行时恐慌。
因此,以下代码为上述问题提供了可行的解决方案:
主要:
var data []customEntry
c.CacheData("Person",&data)
函数本身:
func (cache *MyCache) CacheData(dataQuery string, data interface{}) error {
if keys, err := DataStoreClient.GetAll(cache.ctx, datastore.NewQuery(dataQuery), data); err != nil {
return err
} else {
s := reflect.ValueOf(data).Elem()
for i := 0; i < s.Len(); i++ {
cache.Set(keys[i].Name, s.Index(i), 1)
}
}
}