使用种子作为json.unmarshal到slice结构中

时间:2018-11-27 17:18:45

标签: go

我有一个有趣的问题。

我想向端点发出请求,该端点在HTTP响应中返回给我一系列对象。

然后,我想将该响应解组为切片结构。很容易。

此代码有效:

type Human struct {}
func (h Human) Talk() {}

type CanTalk interface{
    Talk()
}

type Model struct {
    List []CanTalk
}

func main() {
    model := Model{}

    data, err := makeRequestToEndpoint()
    if err != nil {
        // ...
    }

    err = json.Unmarshal(data, &model.List)
    if err != nil {
        // ...
    }

    for _, human := range model.List {
        human.Talk()
    }
}

但是这里有个要点:我想一般地这样做。

我不想为系统中的每个单一类型编写相同的逻辑(因为它们都在单独的文件中),所以我选择使用interface{}而不是[]CanTalk ,这样我就可以将其下的unmarshal和逻辑抽象为一个实用函数。然后为interface{}注入json.Unmarshal的具体类型。

即使该程序可以编译并运行,它也不起作用

type Human struct {}
func (h Human) Talk() {}

type CanTalk interface{
    Talk()
}

type Model struct {
    List interface{} // Using interface{} here instead of []CanTalk
}

func main() {
    model := Model{List:[]Human{}} // Seeding the list with the specified type to unmarshal into

    data, err := makeRequestToEndpoint()
    if err != nil {
        // ...
    }

    err = json.Unmarshal(data, &model.List)
    if err != nil {
        // ...
    }

    if list, ok := model.List.([]interface{}); ok {
        for i := range list {
            // This line is never reached, because "ok == false"
            if human, ok := list[i].(CanTalk); ok {
                // Never reached
                human.Talk()
            }
        }
    }
}

如您所见,元帅不会接我给model.List的种子。解组后model.List的输出仍然是HTTP响应有效载荷的格式(map[string]interface{}或类似的格式),而不是种子的类型,因此无法转换为{{1 }}类型。

这是否有可能,或者实现此目标(缺少真正的泛型)的唯一方法是对系统中每种单独的类型重复解组逻辑?

0 个答案:

没有答案