How to skip existing fields when unmarshal json in golang?

huangapple go评论72阅读模式
英文:

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}

huangapple
  • 本文由 发表于 2022年5月23日 16:27:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/72345431.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定