如果将数组作为& val传递,然后转换为接口{},则更新数组元素 [英] Update array elements if the array in passed as &val and then converted to interface{}

查看:74
本文介绍了如果将数组作为& val传递,然后转换为接口{},则更新数组元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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:原始类型的值.D不能分配给* mongodb.Test [已恢复]恐慌:reflect.Set:原始类型的值.D无法分配给* mongodb.Test

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

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

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

推荐答案

方法如下:

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

在围棋场上运行.

这是与非指针切片元素一起使用的代码的概括:

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 c.Err()
}

这篇关于如果将数组作为& val传递,然后转换为接口{},则更新数组元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆