【问题标题】:Update array elements if the array in passed as &val and then converted to interface{}如果数组作为 &val 传入,然后转换为 interface{},则更新数组元素
【发布时间】:2019-07-14 01:31:26
【问题描述】:

我正在尝试编写一些通用方法(CRUD 方法)以在我的服务之间共享它。以下示例是一个 GetAll() 方法,它返回我的集合中存在的所有文档:

func GetAll(out interface{}) error {
    // mongodb operations

    // iterate through all documents
    for cursor.Next(ctx) {
        var item interface{}
        // decode the document
        if err := cursor.Decode(&item); err != nil {
            return err
        }
        (*out) = append((*out), item)
        // arrays.AppendToArray(out, item) // Read below :)
    }

    return nil // if no error

}

我也尝试了一些反思,但后来:

package arrays

import "reflect"

func AppendToArray(slicePtrInterface interface{}, item interface{}) {
    // enter `reflect`-land
    slicePtrValue := reflect.ValueOf(slicePtrInterface)
    // get the type
    slicePtrType := slicePtrValue.Type()
    // navigate from `*[]T` to `T`
    _ = slicePtrType.Elem().Elem() // crashes if input type not `*[]T`
    // we'll need this to Append() to
    sliceValue := reflect.Indirect(slicePtrValue)
    // append requested number of zeroes
    sliceValue.Set(reflect.Append(sliceValue, reflect.ValueOf(item)))
}

恐慌:reflect.Set:类型primitive.D的值不可分配给类型*mongodb.Test [恢复] 恐慌:reflect.Set:类型primitive.D的值不可分配给类型*mongodb.Test

我想要的是获得与cursor.Decode(&item) 相同的方法(你可以在上面看到)

【问题讨论】:

    标签: go


    【解决方案1】:

    这是怎么做的:

    // GetAll decodes the cursor c to slicep where slicep is a 
    // pointer to a slice of pointers to values.
    func GetAll(ctx context.Context, c *Cursor, slicep interface{}) error {
        // Get the slice. Call Elem() because arg is pointer to the slice.
        slicev := reflect.ValueOf(slicep).Elem()
    
        // Get value type. First call to Elem() gets slice 
        // element type. Second call to Elem() dereferences 
        // the pointer type.
        valuet := slicev.Type().Elem().Elem()
    
        // Iterate through the cursor...
        for c.Next(ctx) {
            // Create new value.
            valuep := reflect.New(valuet)
    
            // Decode to that value.
            if err := c.Decode(valuep.Interface()); err != nil {
                return err
            }
    
            // Append value pointer to slice.
            slicev.Set(reflect.Append(slicev, valuep))
        }
        return c.Err()
    }
    

    这样称呼它:

    var data []*T
    err := GetAll(ctx, c, &data)
    if err != nil {
       // handle error
    }
    

    Run it on the Go Playground.

    下面是处理非指针切片元素的代码的概括:

    func GetAll(ctx context.Context, c *Cursor, slicep interface{}) error {
        slicev := reflect.ValueOf(slicep).Elem()
        valuet := slicev.Type().Elem()
        isPtr := valuet.Kind() == reflect.Ptr
        if isPtr {
            valuet = valuet.Elem()
        }
        for c.Next(ctx) {
            valuep := reflect.New(valuet)
            if err := c.Decode(valuep.Interface()); err != nil {
                return err
            }
            if !isPtr {
                valuep = valuep.Elem()
            }
            slicev.Set(reflect.Append(slicev, valuep))
        }
        return c.Err()
    }
    

    【讨论】:

    • 太棒了!非常感谢 :) 我只是想确保,切片必须是 T 上的指针切片,否则无法填充对吗?
    • 代码采用指针切片。请参阅使用非指针的更新答案。
    猜你喜欢
    • 2012-12-09
    • 2017-04-14
    • 1970-01-01
    • 1970-01-01
    • 2021-07-26
    • 1970-01-01
    • 1970-01-01
    • 2018-08-28
    • 1970-01-01
    相关资源
    最近更新 更多