我正在尝试编写一些通用方法(CRUD方法)以在我的服务之间共享它。以下示例是一种GetAll()方法,该方法返回集合中存在的所有文档:
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:原始类型D的值不能分配给 mongodb.Test类型[已恢复]恐慌:reflect.Set:原始类型D的值不能分配给 mongodb.Test类型
我想要的是与cursor.Decode(&item)(您可以在上面看到的)相同的方法
cursor.Decode(&item)
方法如下:
// 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 }
在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() }