如果将数组作为& val传递,然后转换为接口{},则更新数组元素 [英] Update array elements if the array in passed as &val and then converted to interface{}
问题描述
我正在尝试编写一些通用方法(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屋!