为什么json.Unmarshal使用引用而不是指针?

时间:2013-12-09 19:03:32

标签: json go

来自json.Unmarshal文档的这个示例(为了简单起见,使用Animal而不是[]Animal略有修改)有效,没有错误:

Playground link of working example

// ...
var animals Animal
err := json.Unmarshal(jsonBlob, &animals)
// ...

但是这个略有修改的例子没有:

Playground link of non-working example

// ...
var animals *Animal
err := json.Unmarshal(jsonBlob, animals)
// ...

它显示这个模糊的错误,实际上没有帮助(看起来更像是函数调用而不是错误IMO):

  

json:Unmarshal(nil * main.Animal)

这似乎是因为animals是未初始化的指针。但是文档说(强调我的):

  

Unmarshal将JSON解组为指针指向的值。 如果指针为nil,则Unmarshal会为其指定一个新值以指向它。

那么为什么在第二个例子中解组失败并显示出模糊的错误?

(另外,它是“解组”还是“解组”(一个L)?文档同时使用它们。)

4 个答案:

答案 0 :(得分:31)

您遇到了InvalidUnmarshalError(请参阅lines 109 and 110 in decode.go)。

  

// InvalidUnmarshalError描述传递给Unmarshal的无效参数   // (Unmarshal的参数必须是非零指针。)

似乎文档可以做一些澄清,因为上面的引用和from the Unmarshal source下面的评论似乎相互矛盾。

  

如果指针为nil,则Unmarshal为其指定一个新值以指向。

答案 1 :(得分:26)

因为你的指针是零。

如果您初始化它,则有效:http://play.golang.org/p/zprmV0O1fG

var animals *Animal = &Animal{}

此外,它可以拼写为任何一种方式(单个文档中的一致性会很好):http://en.wikipedia.org/wiki/Marshalling_(computer_science)

答案 2 :(得分:7)

我认为问题在于,虽然你可以将指针传递给nil 到Unmarshal(),但你不能传递 nil指针值

指向nil的指针就像:

var v interface{}
json.Unmarshal(text, &v)

v的值为nil,但指向v的指针是非零指针地址。它是一个非零指针,指向一个nil接口{}(它本身就是一个指针类型)。在这种情况下,Unmarshal不会返回错误。

nil指针就像:

var v *interface{}
json.Unmarshal(text, v)

在这种情况下,v的类型是pointer to an interface{},但与golang中var的任何声明一样,v的初始值是类型的零值。所以v是一个零值指针,这意味着它没有指向内存中的任何有效位置。

https://stackoverflow.com/a/20478917/387176中所述,json.Unmarshal()需要一个指向某事的有效指针,因此它可以改变某些东西(无论是零值结构还是指针)到位。

答案 3 :(得分:0)

我之前有一个类似的情况,但在另一种情况下。 它与Go中的界面概念有关。 如果函数将接口声明为参数或返回值,则调用者必须传递或返回引用

在您的情况下,json.Unmarshal接受接口作为第二个参数