dongqiabei7682 2018-06-10 11:11
浏览 48
已采纳

如何填充传递给函数的接口的切片

I have a small example where I try to populate a []Entry (where Entry is an interface) slice inside a function, this works fine when the argument is a single Entry, but when trying to pass a slice of entries I cannot figure my way through the pointers.

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

And the tests where I try to use this:

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

Depending if I declare GetByCollection(collectionName string, entries []Entry) or GetByCollection(collectionName string, entries *[]Entry) I get either:

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

or

# 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

How should I write so that I can choose the entry type by calling GetByCollection with say either a []Book or []Author slice that get populated?

I probably need to refactor somehow, in the end I like something similar to GORM's Query method (http://gorm.io/docs/query.html#Query) db.Find(&users) but like GetByCollection("books", &books)

  • 写回答

1条回答 默认 最新

  • dqeznd1697 2018-06-10 14:20
    关注

    Reflection is required to work with different slice types. Here's how to do it:

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

    Call it like this:

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

    Playground example

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器