英文:
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() {
// 解析配置文件路径
var configFile string
flag.StringVar(&configFile, "config", "", "配置文件路径")
// 解析选项
flag.IntVar(&Config.Opt1, "opt1", Config.Opt1, "")
flag.StringVar(&Config.Opt2, "opt2", Config.Opt2, "")
// 解析命令行参数
flag.Parse()
// 从config.json文件加载配置选项
if configFile != "" {
if data, err := ioutil.ReadFile(configFile); err != nil {
fmt.Printf("读取配置文件错误:%v\n", err)
} else if err = json.Unmarshal(data, &Config); err != nil {
fmt.Printf("解析配置文件错误:%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}
英文:
I use json
file to configure my program arguments and use flag
package to configure the same arguments.
When some argument parsed by json
file and flag
at the same time, I wish use the arguments parsed through flag
.
The trouble is that the json
file path is also parsed through flag
.
The json path can be obtained after calling flag.parse()
, but the arguments is also parsed, then Unmarshal
json will overwrite the arguments of flag parsing.
example json:
{
"opt1": 1,
"opt2": "hello"
}
example code:
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)
}
program example output:
./foo.exe -opt2 world
out: {Opt1:0 Opt2:world}
./foo.exe -config config.json
out: {Opt1:1 Opt2:hello}
./foo.exe -config config.json -opt2 world
real out: {Opt1:1 Opt2:hello}
hope out: {Opt1:1 Opt2:world}
答案1
得分: 1
一个简单的解决方案是首先解析JSON配置文件,一旦完成,然后再解析CLI参数。
问题在于JSON配置文件也是一个CLI参数。
最简单的解决方案是在解析配置文件后再次调用flag.Parse()
:
// 从config.json文件加载配置选项
if configFile != "" {
if data, err := ioutil.ReadFile(configFile); err != nil {
fmt.Printf("读取配置文件错误:%v\n", err)
} else if err = json.Unmarshal(data, &Config); err != nil {
fmt.Printf("解析配置文件错误:%v\n", err)
}
// 再次解析flags以确保优先级
flag.Parse()
}
第二个flag.Parse()
将覆盖并且优先于来自JSON文件的数据。
通过添加这个,运行
./foo.exe -config config.json -opt2 world
输出将是你所期望的:
{Opt1:1 Opt2:world}
英文:
One easy solution would be to first parse the JSON config file, and once that's done, then proceed to parse CLI arguments.
The problem with this is that the JSON config file is also a CLI arg.
The simplest solution would be to call flag.Parse()
again after parsing the config file:
// 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()
}
The second flag.Parse()
will override and thus have precedence over data coming from the JSON file.
With this addition, running
./foo.exe -config config.json -opt2 world
Output will be what you desire:
{Opt1:1 Opt2:world}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论