我正在尝试从可能具有不同 key 的不同来源解码一些 JSON。例如,我可能有:
{
"a": 1,
"b": 2
}
或者我可能有:
{
"c": 1,
"b": 2
}
在这种情况下,我可以保证“b”会在那里。但是,我希望以相同的方式表示“a”和“c”。实际上,我想要的是:
type MyJson struct {
Init int `json:"a",json:"c"`
Sec int `json:"b"
}
基本上我希望解码器查找任一键并将其设置为 Init
。现在这实际上不起作用(或者我不会发布)。解码第一个给了我想要的,而第二个将 Init
设置为 0。我理想的选择是解码为一个结构,有两种可能性之一:
- 我用上面的多个标签表示结构
- 我定义了多个结构,但我能够选择解码到哪个结构
我试图通过创建两个不同的结构和一个映射来实现数字 2,但似乎我无法创建一个将类型作为第二个值的映射:
type MyJson1 struct {
Init int `json:"a"`
Sec int `json:"b"`
}
type MyJson2 struct {
Init int `json:"c"`
Sec int `json:"b"`
}
有没有办法定义一组行为类似于接口(interface)的结构?也就是说,它们都具有相同的字段,但定义不同。或者也许还有另一种方法。我可以使字段解码“a”和“c”其他字段,然后相应地设置 Init
。但这不会超出几个变体。
谢谢!
最佳答案
一种可能性是定义一个 struct
,它有一个字段用于您可能的输入的所有变体,为了方便起见,为这个结构提供一个方法,它将返回在输入中找到的字段:
type MyJson struct {
A *int `json:"a"`
C *int `json:"c"`
Sec int `json:"b"`
}
func (j *MyJson) Init() int {
if j.A == nil {
return *j.C
}
return *j.A
}
使用它:
inputs := []string{
`{"a": 1, "b": 2}`,
`{"c": 1, "b": 2}`}
for _, input := range inputs {
var my MyJson
if err := json.Unmarshal([]byte(input), &my); err != nil {
panic(err)
}
fmt.Printf("Init: %v, Sec: %v\n", my.Init(), my.Sec)
}
输出,如预期(在 Go Playground 上尝试):
Init: 1, Sec: 2
Init: 1, Sec: 2
还有一个小技巧:
在原始结构中,我们为 2 种可能的变体添加了 2 个字段。我将它们定义为指针,以便我们可以检测在 JSON 输入中找到了哪一个。现在,如果在解码之前我们将这些指针设置为指向相同的值,这就是我们所需要的:无论我们使用哪种输入 JSON 变体,相同的值都将设置在内存中,因此您始终可以读取/引用Init
结构字段:
type MyJson struct {
Init *int `json:"a"`
Init2 *int `json:"c"`
Sec int `json:"b"`
}
func main() {
inputs := []string{
`{"a": 1, "b": 2}`,
`{"c": 1, "b": 2}`}
for _, input := range inputs {
var my MyJson
my.Init = new(int) // Allocate an int
my.Init2 = my.Init // Set Init2 to point to the same value
if err := json.Unmarshal([]byte(input), &my); err != nil {
panic(err)
}
fmt.Printf("Init: %v, Sec: %v\n", *my.Init, my.Sec)
}
}
在 Go Playground 上试试.
您可以创建一个函数来创建和设置您的 MyJson
准备好像这样解码:
func NewMyJson() (my MyJson) {
my.Init = new(int) // Allocate an int
my.Init2 = my.Init // Set Init2 to point to the same value
return
}
因此使用它变得如此简单:
var my = NewMyJson()
err := json.Unmarshal([]byte(input), &my)
Tricked 变体的另一个技巧:
你可以指定Init
字段不是指针,因为Init2
是一个指针并指向Init
就足够了,所以这变得更加简单和可取(但是 NewMyJson
必须返回一个指针):
type MyJson struct {
Init int `json:"a"`
Init2 *int `json:"c"`
Sec int `json:"b"`
}
func NewMyJson() *MyJson {
my := new(MyJson)
my.Init2 = &my.Init // Set Init2 to point to Init
return my
}
关于使用不同的键进行 JSON 解码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28711882/