如何填充作为函数引用传递的接口切片



我有一个小例子,我尝试在函数内填充一个 []Entry(其中 Entry 是一个接口(切片,当参数是单个 Entry 时,这工作正常,但是当尝试传递条目切片时,我无法通过指针找到自己的方式。

package temp
import (
"encoding/json"
uuid "github.com/satori/go.uuid"
)
type BaseEntry struct {
ID uuid.UUID
}
func (entry *BaseEntry) GetID() uuid.UUID {
return entry.ID
}
type Entry interface {
GetID() uuid.UUID
}
func GetByCollection(collectionName string, entries []Entry) {
// This could be a lookup in a database or filesystem
collections := map[string][]string{
"books": []string{
`{"ID": "c8cc718d-94a9-4605-a4bb-05d5aa067fd6", "Title": "Nils Holgersson", "Author": "d89e4a0a-6a65-4754-9090-f8b6c7d6eeec"}`,
`{"ID": "46ad379e-17f2-4961-b615-d4301160f892", "Title": "Ronja rövardotter", "Author": "a1bba636-0700-474f-8fe8-2ad3ec9d061c"}`,
},
"authors": []string{
`{"ID": "d89e4a0a-6a65-4754-9090-f8b6c7d6eeec", "Name": "Selma Lagerlöf"}`,
`{"ID": "a1bba636-0700-474f-8fe8-2ad3ec9d061c", "Name": "Astrid Lindgren"}`,
},
}
if collections[collectionName] != nil {
for _, entryData := range collections[collectionName] {
entry := BaseEntry{}
json.Unmarshal([]byte(entryData), &entry)
*entries = append(*entries, &entry)
}
}
}

以及我尝试使用它的测试:

package temp_test
import (
"testing"
"github.com/mojlighetsministeriet/next/temp"
uuid "github.com/satori/go.uuid"
"github.com/stretchr/testify/assert"
)
type Book struct {
temp.BaseEntry
}
func TestPopulate(test *testing.T) {
books := []Book{}
temp.GetByCollection("books", &books)
assert.NotEqual(test, uuid.Nil, books[0].GetID())
}

根据我声明GetByCollection(collectionName string, entries []Entry)还是GetByCollection(collectionName string, entries *[]Entry)我得到

# github.com/mojlighetsministeriet/next/temp
./main.go:39:4: invalid indirect of entries (type []Entry)

# github.com/mojlighetsministeriet/next/temp_test
./main_test.go:17:32: cannot use &books (type *[]Book) as type * 
[]temp.Entry in argument to temp.GetByCollection

我应该如何编写,以便我可以通过调用 GetByCollection 来选择条目类型,例如填充的 []Book 或 []作者切片?

我可能需要以某种方式重构,最后我喜欢类似于 GORM 的查询方法 (http://gorm.io/docs/query.html#Query( 的东西db.Find(&users)但喜欢GetByCollection("books", &books)

使用不同的切片类型需要反射。具体操作方法如下:

func GetByCollection(collectionName string, result interface{}) {    
collections := map[string][]string{
"books": []string{
`{"ID": "c8cc718d-94a9-4605-a4bb-05d5aa067fd6", "Title": "Nils Holgersson", "Author": "d89e4a0a-6a65-4754-9090-f8b6c7d6eeec"}`,
`{"ID": "46ad379e-17f2-4961-b615-d4301160f892", "Title": "Ronja rövardotter", "Author": "a1bba636-0700-474f-8fe8-2ad3ec9d061c"}`,
},
"authors": []string{
`{"ID": "d89e4a0a-6a65-4754-9090-f8b6c7d6eeec", "Name": "Selma Lagerlöf"}`,
`{"ID": "a1bba636-0700-474f-8fe8-2ad3ec9d061c", "Name": "Astrid Lindgren"}`,
},
}
slice := reflect.ValueOf(result).Elem()
elementType := slice.Type().Elem()
for _, entryData := range collections[collectionName] {
v := reflect.New(elementType)
json.Unmarshal([]byte(entryData), v.Interface())
slice.Set(reflect.Append(slice, v.Elem()))
}
}

这样称呼它:

var books []Book
GetByCollection("books", &books)

游乐场示例

最新更新