为什么 “switch t := policy.Parameter.(type)” 在使用 viper.Unmarshal() 时不起作用?

huangapple go评论90阅读模式
英文:

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

问题

我想要从JSON中解析多种类型,并使用接口来表示实际的结构体,但是当我将结构体发送为interface{}时,它会将其转换为map。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 {}, 为什么它不是一个interface{},我该如何获取它?
		switch t := policy.Parameter.(type) {
		//为什么switch语句不起作用?
		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"`
}


英文:

I want to unmarshal several types from JSON and use the interface to represent the actual struct that it is different. But when I send the struct as interface{} it converts it to a map. The animal.json is:

"{"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"`
}


答案1

得分: 2

这是json解组特性。

如果你将interface{}作为解码器,interface{}的默认json对象类型是map[string]interface{}

你可以在这里看到:

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

bool对应JSON布尔值
float64对应JSON数字
string对应JSON字符串
[]interface{}对应JSON数组
map[string]interface{}对应JSON对象
nil对应JSON null

所以在t := policy.Parameter.(type)中,t的类型是map[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"`
}
英文:

It's json unmarshal feature

If you use an interface{} as a decoder, the default json object for interface{} is map[string]interface{}

You can see it here:

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

So in t := policy.Parameter.(type), the t is map[string]interface{}

For solving your problem, you can try to define another field to distinguish CatParameter or DogParameter

Maybe:

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"`
}

huangapple
  • 本文由 发表于 2019年4月29日 10:49:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/55896369.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定