将接口转换为定义的结构体(struct)Golang。

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

convert interface to defined struct Golang

问题

我正在处理一个实用方法,假设叫做GetConfig(),它读取配置结构并将其返回给调用者。GetConfig() 不知道要读取的配置是什么,但调用者知道它将接收到的结构。

为此,我编写了下面的实用程序:

=========== yaml 文件数据 ==========
apiRouting:
  enableThrottling: true
  formFactor: 4
leasing:
  periodInSecs: 10
  preemptionEnable: false
=========== yaml 文件数据 ==========

func GetConfig() (interface{}, error) {
	fmt.Println("正在读取通用服务配置")
	viper.SetConfigName("service_config")
	viper.AddConfigPath("config/default")
	if err := viper.ReadInConfig(); err != nil {
		return nil, err
	}
	var appConfig interface{}
	if err := viper.Unmarshal(&appConfig); err != nil {
		return nil, err
	}
	return appConfig, nil
}

调用者使用 GetConfig() 如下:(我尝试了两种选项,但都没有成功)

type ApiRouting struct {
	EnableThrottling bool  `json:"enableThrottling"`
	FormFactor       int32 `json:"formFactor"`
}

type Leasing struct {
	PeriodInSecs     int32 `json:"periodInSecs"`
	PreemptionEnable bool  `json:"preemptionEnable"`
}

type ServiceConfig struct {
	ApiRouting ApiRouting `json:"apiRouting"`
	Leasing    Leasing    `json:"leasing"`
}

// 代码片段 [选项 1]
tmpinterface := GetConfig()
myconfig, ok := tmpinterface.(ServiceConfig)
if !ok {
	log.Fatal()
} else {
	println(myconfig)
}

// 代码片段 [选项 2]
tmpinterface := GetConfig()
// 将 map 转换为 JSON 字符串
jsonStr, err := json.Marshal(tmpinterface)
if err != nil {
	fmt.Println(err)
}

// 将 JSON 字符串转换为结构体
var sc ServiceConfig
if err := json.Unmarshal(jsonStr, &sc); err != nil {
	fmt.Println(err)
}

我已经验证了在这两种情况下 tmpinterface 正确地获取了值,但最终 myconfig{} 结构体是空的。

tmpinterface 的值是:

map["apirouting"]:map["enablethrottling":true "formfactor":4] "leasing":map["periodinsecs":10 "preemptionenable":false]
英文:

I am working on a utility method lets say GetConfig(), which reads the config struct and return it to the caller. GetConfig() does not know what config it is going to read, but the caller knows the struct what it is going to receive.

In this regard, I have written a below utility program:

=========== yaml file data ==========
apiRouting:
  enableThrottling: true
  formFactor: 4
leasing:
  periodInSecs: 10
  preemptionEnable: false
=========== yaml file data ==========

func GetConfig() (interface{}, error) {
	fmt.Println("reading generic service config")
	viper.SetConfigName("service_config")
	viper.AddConfigPath("config/default")
	if err := viper.ReadInConfig(); err != nil {
		return nil, err
	}
	var appConfig interface{}
	if err := viper.Unmarshal(&appConfig); err != nil {
		return nil, err
	}
	return appConfig, nil
}

Caller uses GetConfig() like this: (I have tried 2 options, nothing is working)

type ApiRouting struct {
	EnableThrottling bool  `json:"enableThrottling"`
	FormFactor       int32 `json:"formFactor"`
}

type Leasing struct {
	PeriodInSecs     int32 `json:"periodInSecs"`
	PreemptionEnable bool  `json:"preemptionEnable"`
}

type ServiceConfig struct {
	ApiRouting ApiRouting `json:"apiRouting"`
	Leasing    Leasing    `json:"leasing"`
}

// code snipped [option 1]
	tmpinterface := GetConfig()
	myconfig, ok := tmpinterface.(ServiceConfig)
	if !ok {
		log.Fatal()
	} else {
		println(myconfig)
	}

// code snipped [option 2]
	tmpinterface := GetConfig()
	// Convert map to json string
	jsonStr, err := json.Marshal(tmpinterface)
	if err != nil {
		fmt.Println(err)
	}
	
	// Convert json string to struct
	var sc ServiceConfig
	if err := json.Unmarshal(jsonStr, &sc); err != nil {
		fmt.Println(err)
	}

I have verified that tmpinterface is getting the values correctly in both the cases, but finally myconfig{} struct is empty.

tmpinterface value is:

map[%!f(string=apirouting):map[%!f(string=enablethrottling):%!f(bool=true) %!f(string=formfactor):%!f(int=4)] %!f(string=leasing):map[%!f(string=periodinsecs):%!f(int=10) %!f(string=preemptionenable):%!f(bool=false)]]

答案1

得分: 1

@mkopriva,感谢您提供了一个更简洁的解决方案。

func GetConfig(appConfig any) error {
	fmt.Println("读取通用服务配置")
	viper.SetConfigName("service_config")
	viper.AddConfigPath("config/default")
	if err := viper.ReadInConfig(); err != nil {
		return err
	}
	if err := viper.Unmarshal(appConfig); err != nil {
		return err
	}
	return nil
}

func main() {
	var sc ServiceConfig
	if err := GetConfig(&sc); err != nil {
		panic(err)
	}
	fmt.Println(sc)
}
英文:

@mkopriva, thanks for a cleaner solution.

func GetConfig(appConfig any) error {
	fmt.Println("reading generic service config")
	viper.SetConfigName("service_config")
	viper.AddConfigPath("config/default")
	if err := viper.ReadInConfig(); err != nil {
		return err
	}
	if err := viper.Unmarshal(appConfig); err != nil {
		return err
	}
	return nil
}

func main() {
	var sc ServiceConfig
	if err := GetConfig(&sc); err != nil {
		panic(err)
	}
	fmt.Println(sc)
}

huangapple
  • 本文由 发表于 2022年12月5日 14:07:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/74684006.html
匿名

发表评论

匿名网友

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

确定