gpt4 book ai didi

go - 如何在自定义类型的 slice 上进行范围

转载 作者:行者123 更新时间:2023-12-01 22:27:10 24 4
gpt4 key购买 nike

我正在尝试为 Google DataStore 编写 Go 自定义缓存(更准确地说 - 围绕现有缓存库之一的包装器)。在缓存初始化时,它应该接受任何 结构的自定义类型 (具有适当定义的数据存储字段),这将成为所有存储项目的基础。这个想法是可以为反射(reflect)特定 DataStore 条目 (CustomEntry) 结构的各种类型创建/初始化缓存

方法 1 - 存储 reflect.Type 并使用它。 遇到的问题 - 不能遍历自定义类型的 slice

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{})

方法二 - 接受一个接口(interface)数组作为参数。 遇到的问题 = []CustomEntry 不是 []interface{}
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{}

任何建议将不胜感激。

最佳答案

我找到了一个解决方案,并认为它可能值得分享,以防其他人有类似的问题。

最简单的方法是初始化 DataStore 预期接收的结构 slice ,然后将指向它的指针作为参数 (interface{}) 传递给所需的函数。 DataStore,类似于一些解码函数(我尝试过使用 JSON 包)将能够成功地将数据附加到它。

在给定特定类型的情况下,尝试在函数中动态创建 slice ,然后由函数(例如 DataStore 客户端)接受该 slice 可能非常困难(我还没有设法找到方法)。同样,传递一部分接口(interface)(以便于迭代)只会使事情复杂化。

其次,为了迭代数据(例如将其存储在缓存中),有必要:
(1) 检索接口(interface)的底层值(即指针本身) - 这可以使用 reflect.ValueOf(pointerInterface) 来实现,
(2) 取消引用指针,以便我们可以访问底层的、可迭代的结构 slice ——这可以通过调用 .Elem() 来完成,
(3) 使用 .Index(i) 遍历底层 slice 方法(range 将不接受接口(interface),即使底层类型是可迭代的)。

自然地,添加一些 switch-case 语句可能适合确保捕获任何错误而不是导致运行时 panic 。

因此,以下代码为上述问题提供了一个可行的解决方案:

主要:

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)
}
}
}

关于go - 如何在自定义类型的 slice 上进行范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59323831/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com