dqjjw04440 2018-11-27 17:18 采纳率: 0%
浏览 46

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

I have an interesting problem.

I want to make a request to an endpoint that gives me an array of objects back in an HTTP response.

I then want to unmarshal that response into a slice struct. Easy enough.

This code works:

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

But here's the catch: I want to do this generically.

I don't want to write this same logic for every single type in my system (since they're all in separate files), so I opted to use an interface{} as opposed to []CanTalk, so that I could abstract the unmarshal and logic below it to a utility function. The interface{} is then seeded with a concrete type for json.Unmarshal.

Even though this compiles and runs, it does not work:

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

As you can see, the unmarshal does not pick up on the seed that I gave to model.List. The output of model.List after unmarshaling is still in the format of the HTTP response payload (a map[string]interface{} or something like that), not the type of the seed, hence the failure to cast into a CanTalk type.

Is this even possible, or would the only way to achieve this (short of real generics) be to repeat the unmarshal logic for each separate type in my system?

  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
    • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
    • ¥20 有关区间dp的问题求解
    • ¥15 多电路系统共用电源的串扰问题
    • ¥15 slam rangenet++配置
    • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
    • ¥15 ubuntu子系统密码忘记
    • ¥15 保护模式-系统加载-段寄存器
    • ¥15 电脑桌面设定一个区域禁止鼠标操作
    • ¥15 求NPF226060磁芯的详细资料