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

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

报告相同问题?

悬赏问题

  • ¥30 STM32 INMP441无法读取数据
  • ¥100 求汇川机器人IRCB300控制器和示教器同版本升级固件文件升级包
  • ¥15 用visualstudio2022创建vue项目后无法启动
  • ¥15 x趋于0时tanx-sinx极限可以拆开算吗
  • ¥500 把面具戴到人脸上,请大家贡献智慧
  • ¥15 任意一个散点图自己下载其js脚本文件并做成独立的案例页面,不要作在线的,要离线状态。
  • ¥15 各位 帮我看看如何写代码,打出来的图形要和如下图呈现的一样,急
  • ¥30 c#打开word开启修订并实时显示批注
  • ¥15 如何解决ldsc的这条报错/index error
  • ¥15 VS2022+WDK驱动开发环境