一段玄妙的配置读取代码——GO

读到一段GO代码,用作配置文件的加载和解析,它把机制和业务剥离很清晰,可以作为基础层代码,复用在所有需要读取/解析yaml配置文件的项目中。

源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// config.go
func init() {
flag.StringVar(&configFilePath, "c", "", "configuration file path")
}

func Initialize(config interface{}) interface{} {
if !flag.Parsed() {
flag.Parse()
}

if configFilePath != "" {
dat, err := ioutil.ReadFile(configFilePath)
...
err = yaml.Unmarshal(dat, config)
...
globalConfig.Store(config)
} else {
glog.Infof("config file is null. no -c ??")
}
return globalConfig.Load()
}

// Get 返回config实例
func Get() interface{} {
return globalConfig.Load()
}

这段代码妙在复用性上,可以作为基础层代码用在所有需要解析yaml文件的地方。它与具体配置文件对应的数据结构无关,甚至都不需要显式传入配置文件路径,客户端代码可以这么写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// client.go
type Config struct {
Host string `yaml:"host"`
User string `yaml:"user"`
Password string `yaml:"password"`
}

func TestConfig(t *testing.T) { // 测试config的用法
flag.Set("c", "conf.yml")
flag.Parse()

Initialize(&Config{})
config := Get().(*Config)
glog.Infof("Host:%s, User:%s, Password:%s", config.Host, config.User, config.Password)
}

由客户端定义配置文件的数据结构Config,在需要用到内容时做一个类型断言——客户端肯定知道我传入的数据类型,因此对于类型断言是有绝对把握的。
config在init()函数中接收命令行参数,直接把配置文件名对接到参数-c,作为与调用端的约定。调用端无需指定/传入配置文件的路径,即可完成该文件的解析。
这个config.go把机制从业务中完全剥离出来,是机制层代码的典范。反复把玩,妙不可言!可以放到任意需要读取配置文件的项目中。

例程文件放在了https://github.com/palanceli/go-learning/blob/master/yaml/config.go