Go空接口(interface)类型断言和创建副本

标签 go

无法弄清楚如何修改作为指针传递给接受空接口(interface)的函数的结构类型变量

我正在创建一种通过官方 go 驱动程序与 MongoDB 数据库一起使用的库。我正在传递一个结构指针,然后用数据库 (MongoDB cursor.Decode) 中的数据填充该指针。这适用于单个文档,但当我尝试返回文档数组时,只有父文档是正确的,但子文档(嵌入)对于数组中的所有元素保持不变(可能存储引用而不是实际值)。

实际代码:

// passing model pointer to search function
result, _ := mongodb.Search(&store.Time{}, 
                mongodb.D{mongodb.E("transdate", 
                    mongodb.D{mongodb.E("$gte", timeSearch.DateFrom), mongodb.E("$lte", timeSearch.DateTo)})})

...
func Search(model interface{}, filter interface{}) (result ModelCollection, err error) {
    collection := Database.Collection(resolveCollectionName(model))

    var cursor *mongo.Cursor
    cursor, err = collection.Find(Context, filter)
    if err != nil {
        log.Fatal(err)
    } 

    for cursor.Next(Context) {
        if err := cursor.Decode(model); err != nil {
            log.Fatal(err)
        }
        modelDeref := reflect.ValueOf(model).Elem().Interface()
        result = append(result, modelDeref)
    }

    return
}

这是我能想到的最接近 Playground 的例子。我用自己的解码函数替换了 MongoDB cursor.Decode(),但这甚至没有更新父属性。 children 保持不变

https://play.golang.org/p/lswJJY0yl80

预期:

result:[{A:1 Children:[{B:11}]} {A:2 Children:[{B:22}]}]

实际:

result:[{A:init Children:[{B:22}]} {A:init Children:[{B:22}]}]

最佳答案

你正在解码到同一个指针,所以你总是会得到一个 slice ,其中包含的元素的值与你最后解码的元素的值相同。

相反,您应该在每次迭代中初始化模型类型的新实例,然后解码为该实例。

result, _ := mongodb.Search(store.Time{}, ...) // pass in non-pointer type to make life easier

// ...

func Search(model interface{}, filter interface{}) (result ModelCollection, err error) {
    collection := Database.Collection(resolveCollectionName(model))

    var cursor *mongo.Cursor
    cursor, err = collection.Find(Context, filter)
    if err != nil {
        log.Fatal(err)
    } 

    for cursor.Next(Context) {
        v := reflect.New(reflect.TypeOf(model)).Interface() // get a new pointer instance
        if err := cursor.Decode(v); err != nil { // decode
            log.Fatal(err)
        }

        md := reflect.ValueOf(v).Elem().Interface()
        result = append(result, md) // append non-pointer value
    }

    return
}

关于Go空接口(interface)类型断言和创建副本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57180659/

相关文章:

go - 用值作为列表创建字典

go - 在 Go 中旋转数组

json - 解码动态 JSON,忽略已知字段

go - 为什么gdb会输出 fatal error ?

google-app-engine - Golang - Appengine 数据存储过滤器查询与 []byte 比较

if-statement - if else 条件与数学/大

multithreading - 阅读缓存DIY书时的一个Go map线程安全问题

go - 巴泽尔去嵌入数据 "could not embed"

go - 组合或扩展接口(interface)?

将数组解包为参数