在 golang 中解组 json 时如何跳过现有字段?
How to skip existing fields when unmarshal json in golang?
我使用 json
文件来配置我的程序参数,并使用 flag
包来配置相同的参数。
当json
文件和flag
同时解析某些参数时,我希望使用flag
解析的参数。
麻烦的是json
文件路径也是通过flag
解析出来的。
调用flag.parse()
后可以得到json路径,但是也会解析参数,那么Unmarshal
json会覆盖flag解析的参数。
示例json:
{
"opt1": 1,
"opt2": "hello"
}
示例代码:
var Config = struct {
Opt1 int `json:"opt1"`
Opt2 string `json:"opt2"`
}{
Opt1: 0,
Opt2: "none",
}
func main() {
// parse config file path
var configFile string
flag.StringVar(&configFile, "config", "", "config file path")
// parse options
flag.IntVar(&Config.Opt1, "opt1", Config.Opt1, "")
flag.StringVar(&Config.Opt2, "opt2", Config.Opt2, "")
// parse flags
flag.Parse()
// load config options from config.json file
if configFile != "" {
if data, err := ioutil.ReadFile(configFile); err != nil {
fmt.Printf("read config file error: %v\n", err)
} else if err = json.Unmarshal(data, &Config); err != nil {
fmt.Printf("parse config file error: %v\n", err)
}
}
fmt.Printf("%+v", Config)
}
程序示例输出:
./foo.exe -opt2 world
输出:{Opt1:0 Opt2:world}
./foo.exe -config config.json
输出:{Opt1:1 Opt2:hello}
./foo.exe -config config.json -opt2 world
实出:{Opt1:1 Opt2:hello}
希望出来:{Opt1:1 Opt2:world}
一个简单的解决方案是首先解析 JSON 配置文件,完成后,再继续解析 CLI 参数。
问题在于 JSON 配置文件也是一个 CLI 参数。
最简单的解决方案是在解析配置文件后再次调用 flag.Parse()
:
// load config options from config.json file
if configFile != "" {
if data, err := ioutil.ReadFile(configFile); err != nil {
fmt.Printf("read config file error: %v\n", err)
} else if err = json.Unmarshal(data, &Config); err != nil {
fmt.Printf("parse config file error: %v\n", err)
}
// parse flags again to have precedence
flag.Parse()
}
第二个 flag.Parse()
将覆盖并因此优先于来自 JSON 文件的数据。
加上这个,运行
./foo.exe -config config.json -opt2 world
输出将是你想要的:
{Opt1:1 Opt2:world}
我使用 json
文件来配置我的程序参数,并使用 flag
包来配置相同的参数。
当json
文件和flag
同时解析某些参数时,我希望使用flag
解析的参数。
麻烦的是json
文件路径也是通过flag
解析出来的。
调用flag.parse()
后可以得到json路径,但是也会解析参数,那么Unmarshal
json会覆盖flag解析的参数。
示例json:
{
"opt1": 1,
"opt2": "hello"
}
示例代码:
var Config = struct {
Opt1 int `json:"opt1"`
Opt2 string `json:"opt2"`
}{
Opt1: 0,
Opt2: "none",
}
func main() {
// parse config file path
var configFile string
flag.StringVar(&configFile, "config", "", "config file path")
// parse options
flag.IntVar(&Config.Opt1, "opt1", Config.Opt1, "")
flag.StringVar(&Config.Opt2, "opt2", Config.Opt2, "")
// parse flags
flag.Parse()
// load config options from config.json file
if configFile != "" {
if data, err := ioutil.ReadFile(configFile); err != nil {
fmt.Printf("read config file error: %v\n", err)
} else if err = json.Unmarshal(data, &Config); err != nil {
fmt.Printf("parse config file error: %v\n", err)
}
}
fmt.Printf("%+v", Config)
}
程序示例输出:
./foo.exe -opt2 world
输出:{Opt1:0 Opt2:world}
./foo.exe -config config.json
输出:{Opt1:1 Opt2:hello}
./foo.exe -config config.json -opt2 world
实出:{Opt1:1 Opt2:hello}
希望出来:{Opt1:1 Opt2:world}
一个简单的解决方案是首先解析 JSON 配置文件,完成后,再继续解析 CLI 参数。
问题在于 JSON 配置文件也是一个 CLI 参数。
最简单的解决方案是在解析配置文件后再次调用 flag.Parse()
:
// load config options from config.json file
if configFile != "" {
if data, err := ioutil.ReadFile(configFile); err != nil {
fmt.Printf("read config file error: %v\n", err)
} else if err = json.Unmarshal(data, &Config); err != nil {
fmt.Printf("parse config file error: %v\n", err)
}
// parse flags again to have precedence
flag.Parse()
}
第二个 flag.Parse()
将覆盖并因此优先于来自 JSON 文件的数据。
加上这个,运行
./foo.exe -config config.json -opt2 world
输出将是你想要的:
{Opt1:1 Opt2:world}