所以,我有结构P.我需要将一些json数据解组成P,但有时它是嵌入式struct,Embedded。在任何一种情况下,我从API解组json并需要格式化“格式化”字段。在嵌入式案例中,我的unmarshaller似乎没有被调用。
package main
import (
"encoding/json"
"fmt"
)
type P struct {
Name string `json:"name"`
Formatted string `json:"formatted"`
}
type Embedded struct {
A struct {
B struct {
*P
} `json:"b"`
} `json:"a"`
}
func (p *P) UnmarshalJSON(b []byte) error {
type Alias P
a := &struct {
*Alias
}{
Alias: (*Alias)(p),
}
if err := json.Unmarshal(b, &a); err != nil {
return err
}
a.Formatted = fmt.Sprintf("Hi, my name is %v", a.Name)
return nil
}
func simple() {
b := []byte(`{"name":"bob"}`)
p := &P{}
if err := json.Unmarshal(b, &p); err != nil {
panic(err)
}
fmt.Printf("normal: %+v\n", p)
}
func embedded() {
b := []byte(`{"a":{"b":{"name":"bob"}}}`)
e := &Embedded{}
if err := json.Unmarshal(b, &e); err != nil {
panic(err)
}
fmt.Printf("embedded: %+v\n", e.A.B.P)
}
func main() {
simple()
embedded()
}
(我意识到我可以摆脱自定义unmarshaller并创建一个格式化名称的方法,但想知道这种方式是否可行。)
答案 0 :(得分:2)
我不知道解释所有原因,我只列出哪些有效,哪些无效。更有知识的人可以填写你背后的原因。
当B为*struct
时,以下情况有效,不确定原因。
type Embedded struct {
A struct {
B *struct {
P
} `json:"b"`
} `json:"a"`
}
以下也有效。我猜测使用匿名结构在最后一个结果中有一些效果,因为这里不需要*struct
。
type embedP struct {
P
}
type Embedded struct {
A struct {
B embedP `json:"b"`
} `json:"a"`
}
如果*P
已初始化,则以下情况有效。
type embedP struct {
*P
}
type intermediate struct {
B embedP `json:"b"`
}
type Embedded struct {
A intermediate `json:"a"`
}
e := &Embedded{A:intermediate{embedP{P:&P{}}}}
但同样的事情不适用于匿名结构。
type Embedded struct {
A struct {
B struct {
*P
} `json:"b"`
} `json:"a"`
}
e := &Embedded{A : struct{B struct{*P}`json:"b"`}{B: struct{*P}{&P{}}}}
其他改进
如果p := &P{}
已经是指针,则无需在json.Unmarshal中传递& p。 json.Unmarshal(b, p)
就足够了。与e := &Embedded{}
相同。
答案 1 :(得分:2)
为了扩展@ John的答案,请查看json解码器的源代码,特别是方法indirect(v reflect.Value, decodingNull bool)
第442-483行。
//间接行走v根据需要分配指针,
//直到它到达非指针。
//如果遇到Unmarshaler,间接停止并返回 //如果decodeNull为true,则间接在最后一个指针处停止,因此可以将其设置为nil。
该方法返回(vec (concat [:aggs] [:bucket-aggregation :aggs]))
,json.Unmarshaler
和encoding.TextUnmarshaler
的值。 在当前实现中,在方法内部,基本上执行了以下步骤
v
不是指针,它将立即返回,而不检查v
是否实现v
。无论json.Unmarshaler/encoding.TextUnmarshaler
是否实现自定义unmarshaller,该方法都会为两个unmarshaller分配nil
。B
是指针,它将检查v
是否实现v
。在这种情况下,如果json.Unmarshaler/encoding.TextUnmarshaler
为零,则会为v
分配一个新值。如果v
定义为
Embedded
当将type Embedded struct {
A struct {
B struct {
*P
} `json:"b"`
} `json:"a"`
}
解码为字段"b":{"name":"bob"}
时,由于B
不是指针,因此(1)适用。结果,自定义unmarshaller返回为B
,因此永远不会被调用。 json解码器使用默认的unmarshaller将json值解码为nil
的字段。
如果B
定义为
Embedded
因为字段type Embedded struct {
A struct {
*B struct {
P
} `json:"b"`
} `json:"a"`
}
是指针,所以(2)适用。解码器将新B
分配给struct{*P}
,检测到B
实现了自定义unmarshaller,然后按预期调用它。以下声明
B
如果预先分配type Embedded struct {
A struct {
*B struct {
*P
} `json:"b"`
} `json:"a"`
}
,也可以。
P
如果未预先分配,则在(2)中,解码器会将//...
e := Embedded{}
e.A.B = &struct{ *P }{P: &P{}}
//...
分配给&struct{*P}{}
,然后使用B
调用自定义的unmarshaller。结果,在unmarshall期间,B.P == nil
无法捕获json值。
注意强>:
我不确定它是否是所希望的行为,我无法找到与嵌入式结构相关的明确文档。