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

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

convert interface to defined struct Golang

问题

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

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

  1. =========== yaml 文件数据 ==========
  2. apiRouting:
  3. enableThrottling: true
  4. formFactor: 4
  5. leasing:
  6. periodInSecs: 10
  7. preemptionEnable: false
  8. =========== yaml 文件数据 ==========
  9. func GetConfig() (interface{}, error) {
  10. fmt.Println("正在读取通用服务配置")
  11. viper.SetConfigName("service_config")
  12. viper.AddConfigPath("config/default")
  13. if err := viper.ReadInConfig(); err != nil {
  14. return nil, err
  15. }
  16. var appConfig interface{}
  17. if err := viper.Unmarshal(&appConfig); err != nil {
  18. return nil, err
  19. }
  20. return appConfig, nil
  21. }

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

  1. type ApiRouting struct {
  2. EnableThrottling bool `json:"enableThrottling"`
  3. FormFactor int32 `json:"formFactor"`
  4. }
  5. type Leasing struct {
  6. PeriodInSecs int32 `json:"periodInSecs"`
  7. PreemptionEnable bool `json:"preemptionEnable"`
  8. }
  9. type ServiceConfig struct {
  10. ApiRouting ApiRouting `json:"apiRouting"`
  11. Leasing Leasing `json:"leasing"`
  12. }
  13. // 代码片段 [选项 1]
  14. tmpinterface := GetConfig()
  15. myconfig, ok := tmpinterface.(ServiceConfig)
  16. if !ok {
  17. log.Fatal()
  18. } else {
  19. println(myconfig)
  20. }
  21. // 代码片段 [选项 2]
  22. tmpinterface := GetConfig()
  23. // 将 map 转换为 JSON 字符串
  24. jsonStr, err := json.Marshal(tmpinterface)
  25. if err != nil {
  26. fmt.Println(err)
  27. }
  28. // 将 JSON 字符串转换为结构体
  29. var sc ServiceConfig
  30. if err := json.Unmarshal(jsonStr, &sc); err != nil {
  31. fmt.Println(err)
  32. }

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

tmpinterface 的值是:

  1. 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:

  1. =========== yaml file data ==========
  2. apiRouting:
  3. enableThrottling: true
  4. formFactor: 4
  5. leasing:
  6. periodInSecs: 10
  7. preemptionEnable: false
  8. =========== yaml file data ==========
  9. func GetConfig() (interface{}, error) {
  10. fmt.Println("reading generic service config")
  11. viper.SetConfigName("service_config")
  12. viper.AddConfigPath("config/default")
  13. if err := viper.ReadInConfig(); err != nil {
  14. return nil, err
  15. }
  16. var appConfig interface{}
  17. if err := viper.Unmarshal(&appConfig); err != nil {
  18. return nil, err
  19. }
  20. return appConfig, nil
  21. }

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

  1. type ApiRouting struct {
  2. EnableThrottling bool `json:"enableThrottling"`
  3. FormFactor int32 `json:"formFactor"`
  4. }
  5. type Leasing struct {
  6. PeriodInSecs int32 `json:"periodInSecs"`
  7. PreemptionEnable bool `json:"preemptionEnable"`
  8. }
  9. type ServiceConfig struct {
  10. ApiRouting ApiRouting `json:"apiRouting"`
  11. Leasing Leasing `json:"leasing"`
  12. }
  13. // code snipped [option 1]
  14. tmpinterface := GetConfig()
  15. myconfig, ok := tmpinterface.(ServiceConfig)
  16. if !ok {
  17. log.Fatal()
  18. } else {
  19. println(myconfig)
  20. }
  21. // code snipped [option 2]
  22. tmpinterface := GetConfig()
  23. // Convert map to json string
  24. jsonStr, err := json.Marshal(tmpinterface)
  25. if err != nil {
  26. fmt.Println(err)
  27. }
  28. // Convert json string to struct
  29. var sc ServiceConfig
  30. if err := json.Unmarshal(jsonStr, &sc); err != nil {
  31. fmt.Println(err)
  32. }

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

tmpinterface value is:

  1. 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,感谢您提供了一个更简洁的解决方案。

  1. func GetConfig(appConfig any) error {
  2. fmt.Println("读取通用服务配置")
  3. viper.SetConfigName("service_config")
  4. viper.AddConfigPath("config/default")
  5. if err := viper.ReadInConfig(); err != nil {
  6. return err
  7. }
  8. if err := viper.Unmarshal(appConfig); err != nil {
  9. return err
  10. }
  11. return nil
  12. }
  13. func main() {
  14. var sc ServiceConfig
  15. if err := GetConfig(&sc); err != nil {
  16. panic(err)
  17. }
  18. fmt.Println(sc)
  19. }
英文:

@mkopriva, thanks for a cleaner solution.

  1. func GetConfig(appConfig any) error {
  2. fmt.Println("reading generic service config")
  3. viper.SetConfigName("service_config")
  4. viper.AddConfigPath("config/default")
  5. if err := viper.ReadInConfig(); err != nil {
  6. return err
  7. }
  8. if err := viper.Unmarshal(appConfig); err != nil {
  9. return err
  10. }
  11. return nil
  12. }
  13. func main() {
  14. var sc ServiceConfig
  15. if err := GetConfig(&sc); err != nil {
  16. panic(err)
  17. }
  18. fmt.Println(sc)
  19. }

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:

确定