在项目开发中,通常需要提供重要参数的配置功能,以适应用户的不同使用要求。常见的方式是程序读取配置文件或用户输入来对相关参数进行更改与配置。
在参数配置的生效性上,存在一套优先级逻辑:命令行参数>配置文件参数>硬编码参数。(站长polaris注:其实还有环境变量)
配置过程
首先,定义配置对象Config结构体
type Config struct {
LogLevel string `json:"log_level"`
Port int `json:"port"`
}
1. 硬编码
硬编码的方式非常简单,就是在生成Config对象时,将参数的值直接写入对象之中。
func DefaultConfig() *Config {
return &Config{
LogLevel: "info",
Port: 8080,
}
}
2. 配置文件
日常开发中,配置文件常见有以下几种格式:
json 文件
xml 文件
yaml 文件
toml 文件
ini 文件
在上文定义的Config结构体对象,在属性中定义了json的tag信息,因此可用于解析json格式的配置文件。对于其他的文件格式,相应地在Config结构体中配置对应的tag信息即可。
本例的配置信息写在config.json中,内容如下
{
"log_level": "debug",
"port": 9090
}
加载配置文件信息,利用json.Unmarshal方法,将配置文件中json信息绑定于Config对象(注意:只有大写开头的字段才具有json导出性)。
func loadConfig(configPath string) *Config {
cfg := Config{}
buf, err := ioutil.ReadFile(configPath)
if err != nil {
panic(err)
}
err = json.Unmarshal(buf, &cfg)
if err != nil {
panic(err)
}
return &cfg
}
3. 命令行读取
利用内置flag包,定义和读取用户的输入参数。
const (
nLog = "log"
nPort = "p"
)
var (
logLevel = flag.String(nLog, "debug", "log level")
port = flag.Int(nPort, 8080, "listen port")
cfgPath = flag.String("path", "./config.json", "config file path")
)
func overrideConfig(cfg *Config) {
m := make(map[string]bool)
flag.Visit(func(f *flag.Flag) {
m[f.Name] = true
})
if m[nLog] {
cfg.LogLevel = *logLevel
}
if m[nPort] {
cfg.Port = *port
}
}
4. 运行
执行命令 go run main.go -log error -p 7070,其中-log参数和-p是通过flag包定义。
func main() {
flag.Parse()
cfg := DefaultConfig() // 硬编码
fmt.Println(cfg) // 输出&{info 8080}
if *cfgPath != "" {
cfg = loadConfig(*cfgPath) // 读取配置文件
}
fmt.Println(cfg) // 输出&{debug 9090}
overrideConfig(cfg) // 读取用户输入
fmt.Println(cfg) // 输出&{error 7070}
}
总结来说,参数生效过程如下图所示。
在实际参数更改过程中,基于安全,需要做参数检查工作。例如检查参数类型,参数值范围是否满足等。参数生效后,其值就会随着Config对象被程序执行于内存中,供全局使用,后续对参数的更改就是基于内存中值的修改。
推荐阅读
Go 创建对象时,如何优雅的传递初始化参数
喜欢本文的朋友,欢迎关注“Go语言中文网”:
Go语言中文网启用微信学习交流群,欢迎加微信:274768166,投稿亦欢迎