有条件地将毒蛇配置(toml)解组为结构的惯用方法

我是 Go 新手,想知道如何以惯用的方式解决以下问题:


我正在使用 viper 将配置文件加载到程序中。我选择 toml 格式是因为我想要一个配置文件,它可以指定几种不同格式的所需输入:例如,Alpha 提供程序需要一个 apikey,而 Beta 提供程序需要用户名和密码。


[alpha]

apikey = "123"

domain = "example.com"


# [beta]

# username = ""

# password = ""

# domain = ""

type ProviderService interface {                                 

    PrintDomain()                                                

}                                                                

                                                                 

type Provider struct {                                           

    Alpha `mapstructure:"alpha"`                                 

    Beta  `mapstructure:"beta"`                                                     

}                                                                

                                                                 

type Alpha struct {                                              

    Apikey string `mapstructure:"apikey"`                        

    Domain string `mapstructure:"domain"`                        

}                                                                

                                                                 

type Beta struct {                                               

    Username string `mapstructure:"username"`                    

    Password string `mapstructure:"password"`                    

    Domain   string `mapstructure:"domain"`                      

}                                                                


上面的代码导致{Alpha:{Apikey:123 Domain:example.com} Beta:{Username: Password: Domain:}}空/未使用的结构仍然存在。


最终,我希望 ProviderService 接口与提供者无关,因此我可以简单地调用provider.PrintDomain()而不是provider.Alpha.PrintDomain()让代码中散布着 if/else 语句。我也对构建代码以实现这一结果的其他方式持开放态度。


提前致谢!


皈依舞
浏览 137回答 2
2回答

侃侃尔雅

一种可能的方法是使用反射func&nbsp;main()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;provider&nbsp;:=&nbsp;loadConfig() &nbsp;&nbsp;&nbsp;&nbsp;fmt.Printf("%+v\n",&nbsp;provider) &nbsp;&nbsp;&nbsp;&nbsp;v&nbsp;:=&nbsp;reflect.ValueOf(provider) &nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;i&nbsp;:=&nbsp;0;&nbsp;i&nbsp;<&nbsp;v.NumField();&nbsp;i++&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;field&nbsp;:=&nbsp;v.Field(i) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fmt.Println("domain:",&nbsp;field.FieldByName("Domain")) &nbsp;&nbsp;&nbsp;&nbsp;}}它将打印 Alpha 或 Beta 结构的“域”字段。去游乐场

繁华开满天机

这就是我最终得到的结果,它允许我根据 toml 文件中指定的内容有条件地加载结构,并且仍然使用接口将其视为结构不可知论。如果有人有任何关于将其重构为更惯用的技巧,请告诉我!type ProviderService interface {&nbsp; &nbsp; DoAThing()}type Alpha struct {&nbsp; &nbsp; Apikey string `mapstructure:"apikey"`&nbsp; &nbsp; Domain string `mapstructure:"domain"`}type Beta struct {&nbsp; &nbsp; Username string `mapstructure:"username"`&nbsp; &nbsp; Password string `mapstructure:"password"`&nbsp; &nbsp; Domain&nbsp; &nbsp;string `mapstructure:"domain"`}func main() {&nbsp; &nbsp; provider := loadConfig()&nbsp; &nbsp; if provider == nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Fatal("unable to parse config file")&nbsp; &nbsp; }&nbsp; &nbsp; provider.DoAThing()}func (a Alpha) DoAThing() {&nbsp; &nbsp; fmt.Println("domain", a.Domain)}func (b Beta) DoAThing() {&nbsp; &nbsp; fmt.Println("domain", b.Domain)}func loadConfig() ProviderService {&nbsp; &nbsp; viper.AddConfigPath("./")&nbsp; &nbsp; viper.SetConfigName("config")&nbsp; &nbsp; viper.SetConfigType("toml")&nbsp; &nbsp; err := viper.ReadInConfig()&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; panic(fmt.Errorf("Fatal error config file: %w \n", err))&nbsp; &nbsp; }&nbsp; &nbsp; var a Alpha&nbsp; &nbsp; _ = viper.UnmarshalKey("alpha", &a)&nbsp; &nbsp; if a != (Alpha{}) {&nbsp; &nbsp; &nbsp; &nbsp; return a&nbsp; &nbsp; }&nbsp; &nbsp; var b Beta&nbsp; &nbsp; _ = viper.UnmarshalKey("beta", &b)&nbsp; &nbsp; if b != (Beta{}) {&nbsp; &nbsp; &nbsp; &nbsp; return b&nbsp; &nbsp; }&nbsp; &nbsp; return nil}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go