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

问题描述:

json.Unmarshal文档(稍加修改,使用简单的Animal代替[]Animal)这个例子的作品,没有任何错误:为什么json.Unmarshal使用引用而不是指针?

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:解组(无* main.Animal)

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

Unmarshal将JSON解组到指针指向的值。 如果指针为零,Unmarshal会为它指定一个新值。

那么为什么在第二个例子中unmarshaling失败并显示不明确的错误?

(此外,有 “解组” 或 “拆封”(一个L)?该文档同时使用。)

你遇到了一个InvalidUnmarshalError(见lines 109 and 110 in decode.go)。

// InvalidUnmarshalError描述传递给Unmarshal的无效参数。
// (以解组的参数必须是一个非空指针。)

看来文档可以做一些澄清,上述报价和低于from the Unmarshal source的意见做似乎相互矛盾。

如果指针为零,Unmarshal会为它指定一个新值。

因为你的指针是零。

如果你初始化它的工作原理:http://play.golang.org/p/zprmV0O1fG

var animals *Animal = &Animal{} 

而且,它可以被拼写为任何一种方式(一致性在一个单一的文档将是很好,虽然):http://en.wikipedia.org/wiki/Marshalling_(computer_science)

+0

好的,但是这对于Unmarshal文档意味着什么:“如果指针为零,Unmarshal会为它指定一个新值。”为什么我们必须初始化它,如果Unmarshal应该为我们做呢? – Matt

+0

哈哈,是的,我刚刚在你的问题中看到了。那么,如果你传入指针的引用,它也分配它。 http://play.golang.org/p/3KP7pPKmBp –

+0

有趣。那么,我对“指针”意味着什么不正确或文档错误的理解是什么?因为我在这里看到的所有工作都是引用,而不是指针。 – Matt

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

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

我认为问题是,虽然您可以将指针传递给无 Unmarshal(),您无法传递零指针值

的指针为nil将是这样的:

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

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

甲零指针将是这样的:

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

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

https://stackoverflow.com/a/20478917/387176提到的,json.Unmarshal()需要一个有效的指针东西,因此它可以改变一些(可能是一个零值结构或指针)在适当位置。