为什么 "switch t := policy.Parameter.(type)" 不适用于 viper.Unmarshal()

why the "switch t := policy.Parameter.(type)" does not work with viper.Unmarshal()

我想从 JSON 中解组几个类型并使用接口来表示它不同的实际结构。但是当我将结构作为 interface{} 发送时,它会将其转换为地图。 animal.json 是:

"{"type":"cat","policies":[{"name":"kitty","parameter":{"duration":600,"percent":90}}]}"
package main

import (
    "reflect"

    log "github.com/sirupsen/logrus"
    "github.com/spf13/viper"
)

func main() {
    var err error
    animal := New()
    viper.SetConfigType("json")
    viper.SetConfigName("animal")
    viper.AddConfigPath("~/Desktop/")
    viper.AddConfigPath(".")
    if err := viper.ReadInConfig(); err != nil {
        return
    }

    if err = viper.Unmarshal(&animal); err != nil {
        return
    }
    for _, policy := range animal.Policies {
        log.Info(policy.Name)
        log.Info(policy.Parameter)
        //INFO[0000] map[duration:600 percent:90]
        log.Info(reflect.TypeOf(policy.Parameter))
        //INFO[0000] map[string]interface {}, Why is it not an interface{} and how do I get it?
        switch t := policy.Parameter.(type) {
        //why does the switch not work?
        case *CatParameter:
            log.Info("cat", t)
        case *DogParameter:
            log.Info("dog", t)
        }
    }
}

func New() *Animal {
    var animal Animal
    animal.Type = "cat"
    return &animal
}

type Animal struct {
    Type     string   `json:"type" form:"type"`
    Policies []Policy `json:"policies" form:"policies"`
}

type CatParameter struct {
    Duration int `json:"duration"`
    Percent  int `json:"percent"`
}

type DogParameter struct {
    Percent   int    `json:"percent"`
    Duration  int    `json:"duration"`
    Operation string `json:"operation"`
}

type Policy struct {
    Name      string      `json:"name"`
    Parameter interface{} `json:"parameter"`
}


它是 json 解组功能

如果您使用 interface{} 作为解码器,则 interface{} 的默认 json 对象是 map[string]interface{}

你可以在这里看到:

https://godoc.org/encoding/json#Unmarshal

bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null

所以在t := policy.Parameter.(type)中,tmap[string]interface{}

为了解决你的问题,你可以尝试定义另一个字段来区分CatParameterDogParameter

也许:

type Policy struct {
    Name      string      `json:"name"`
    Parameter Parameter   `json:"parameter"`
}

type Parameter struct {
    Name      string `json:"name"`   // cat or dog
    Percent   int    `json:"percent,omitempty"`
    Duration  int    `json:"duration,omitempty"`
    Operation string `json:"operation,omitempty"`
}