doumeng1897 2019-07-14 01:31
浏览 27
已采纳

如果将数组作为&val传递,然后转换为接口{},则更新数组元素

I am trying to code some generic methods (CRUD approach) to share it between my services. The following example is a GetAll() method that returns all the documents present in my collection:

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

}

I also tried with some reflection, but then:

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

panic: reflect.Set: value of type primitive.D is not assignable to type *mongodb.Test [recovered] panic: reflect.Set: value of type primitive.D is not assignable to type *mongodb.Test

What I would like is to get the same approach as cursor.Decode(&item) (you can see above)

  • 写回答

1条回答 默认 最新

  • douwei1174 2019-07-14 02:24
    关注

    Here's how to do it:

    // 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 nil
    }
    

    Call it like this:

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

    Run it on the Go Playground.

    Here's a generalization of the code to work with non-pointer slice elements:

    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 nil
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥35 平滑拟合曲线该如何生成
  • ¥100 c语言,请帮蒟蒻写一个题的范例作参考
  • ¥15 名为“Product”的列已属于此 DataTable
  • ¥15 安卓adb backup备份应用数据失败
  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站
  • ¥50 成都蓉城足球俱乐部小程序抢票
  • ¥15 yolov7训练自己的数据集