我有一个struct
,它嵌入一个指向另一个struct
的嵌入指针。当我使用默认的json.unmarshal
行为时,它可以完美地工作。但是,当我为嵌入式struct
的类型而不是为外部struct
实现unmarshaljson
时,就会出现空指针取消引用的恐慌。
如果我也为外部struct
类型实现unmarshaljson
,那么它就可以工作了。但是,外部结构有许多字段,我不想手动解封。
unmarshaljson
会导致恐慌?unmarshaljson
?unmarshaljson
?注意:这里有一个标题类似的问题,“当嵌入式类型具有UnmarshalJSON时,JSON.Unmarshal失败”,但这里的问题与我的问题不同。
TL;DR:这个问题的其余部分只是上面的一个冗长的例子。
(示例的play.golang.org版本)
(例如,简化了--它并不真正需要自己的unmarshaljson
,但它演示了这个问题。)
type Obj struct {
X int `json:"x"`
}
type Container struct {
*Obj
Y int `json:"y"`
}
调用解封:
func main() {
b := []byte(`{"x": 5, "y": 3}`)
c := &Container{}
err := json.Unmarshal(b, c)
if err != nil {
fmt.Printf("error ummarshalling json: %+v\n", err)
return
}
fmt.Printf("unmarshalled: %+v --> %+v\n", c, c.Obj)
}
如果不实现任何unmarshaljson
函数,就可以很好地工作:
unmarshalled: &{Obj:0x416080 Y:3} --> &{X:5}
func (o *Obj) UnmarshalJSON(b []byte) (err error) {
m := make(map[string]int)
err = json.Unmarshal(b, &m)
if err != nil {
return nil
}
o.X = m["x"] // the line indicated by panic
return nil
}
panic: runtime error: invalid memory address or nil pointer dereference
[...]
main.(*Obj).UnmarshalJSON(0x0, 0x416030, 0x10, 0x10, 0x0, 0x0)
/tmp/sandbox185809294/main.go:18 +0x130
[...]
func (c *Container) UnmarshalJSON(b []byte) (err error) {
m := make(map[string]int)
err = json.Unmarshal(b, &m)
if err != nil {
return err
}
c.Obj = &Obj{X: m["x"]}
c.Y = m["y"]
return nil
}
但是,如果真正的容器
和真正的obj
都有比这更多的字段,每个字段都有不同的类型,那么以这种方式手动解封容器
就会变得乏味。
问题:有没有更简单的方法来防止这种恐慌?
因为默认行为检查nil
,而您的自定义解封程序不检查。在unmarshalJSON
中需要一些逻辑来检查O
是否为nil
并进行适当的操作,而不是假设O
不是nil
(通过尝试访问其中一个字段),从而触发恐慌。
func (o *Obj) UnmarshalJSON(b []byte) (err error) {
if o == nil {
return nil // maybe? What do you want to happen in this case?
}
m := make(map[string]int)
err = json.Unmarshal(b, &m)
if err != nil {
return nil
}
o.X = m["x"] // the line indicated by panic
return nil
}
另外,您的*obj
字段不是“匿名字段”,而是嵌入式字段:https://golang.org/ref/spec#struct_types
问题内容: JPA实体类是否可以包含两个嵌入式()字段?一个例子是: 在这种情况下,a 可以包含两个实例-家庭和工作。我在Hibernate的实现中使用JPA。当我使用Hibernate Tools生成架构时,它仅嵌入一个。我想要的是两个嵌入式实例,每个实例的列名都经过区分或在前面加上一些前缀(例如home和work)。我知道,但是这要求每个属性都应单独覆盖。如果嵌入的对象()变大,那么这会变得很
操作步骤: 菜单栏: Refactor —> Encapsulate Field ...
问题内容: 我有一个结构: 我在全球范围内存储一部分用户: 最后,http处理程序: 所以,为什么会这样,我的意思是我发送“加载”请求,它加载数据,设置为。但是在下一次调用“ newData”请求时,是? 以防万一,这里是: 编辑: 哪里来的: 问题答案: 这是因为您对 副本 进行操作,而不是对slice元素本身进行操作。 在函数中,make循环遍历的元素的副本,然后返回此副本的地址。因此,稍后您
问题内容: 我正在研究一个示例程序来回答关于SO的另一个问题,但发现自己对以下代码无法编译的事实感到困惑。 https://play.golang.org/p/wxBGcgfs1o 错误是; 是否可以在静态初始化程序中从嵌入式类型设置字段的值?怎么样?在我看来,这似乎是一个编译器错误;如果我前面没有源代码并且熟悉类型,那么我会在墙上碰头说“显然FName存在于B上,编译器在说什么!!!!!”。 很
问题内容: 我想在结构上定义一个方法来验证http请求。但是我在访问结构域时遇到一些问题。 有我的代码。 运行此代码时,得到以下结果 有什么方法可以访问Validate2()方法上的Validate()方法上的结构字段? 问题答案: 您不能从内部结构访问外部结构字段。仅内部字段来自外部。您可以做的是:
问题内容: 背景 我已经做了大量的规范阅读和代码测试,我认为答案是否定的,但是我想确保自己没有遗漏任何东西。 目标 基本上,我正在尝试为Go创建Active Record样式的ORM,因为我喜欢它的可读性以及从后端数据存储中抽象出来的方式。我宁愿写,也不愿在用户结构上嵌入常见的CRUD方法。 例 http://play.golang.org/p/cWyqqVSKGH 题 有没有一种方法可以使嵌入式