为了账号安全,请及时绑定邮箱和手机立即绑定

如何对自定义类型的切片进行范围调整

如何对自定义类型的切片进行范围调整

Go
UYOU 2023-08-14 15:02:01
我正在尝试为 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不是[]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 []CustomEntryCache.CacheData("Person", data)// ERROR: Cannot use 'data' (type []CustomEntry) as type []interface{}任何建议将不胜感激。
查看完整描述

1 回答

?
慕后森

TA贡献1802条经验 获得超5个赞

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


最简单的方法是启动 DataStore 预期接收的结构切片,然后将指向它的指针作为参数 (interface{}) 传递到所需的函数中。DataStore,类似于一些解组函数(我已经尝试使用 JSON 包)将能够成功地将数据附加到其中。


尝试在给定某种类型的情况下在函数内动态创建切片,然后由函数(例如 DataStore 客户端)接受该切片可能会非常困难(我还没有找到一种方法来做到这一点)。同样,传递一部分接口(以允许轻松迭代)只会使事情变得复杂。


其次,为了迭代数据(例如将其存储在缓存中),有必要:(1)检索接口的底层值(即指针本身) - 这可以使用以下方式实现,(2)取消reflect.ValueOf(pointerInterface)引用指针,以便我们获得对底层可迭代结构切片的访问权 - 这可以通过调用来完成.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)

        }

    }

}


查看完整回答
反对 回复 2023-08-14
  • 1 回答
  • 0 关注
  • 109 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信