3 回答
TA贡献1850条经验 获得超11个赞
json 包没有理由“停在一个指针”,因为指针在 json 中没有任何意义。它必须继续遍历树才能找到要写入的值。由于 json 包将允许将相同的值解组为Typeor *Type,因此它应该能够将其解组为**Type,这也是 Go 中的有效类型。
例如,如果Person使用指针定义来区分 nil 和零值,并且您正在解组为 的切片[]*Person,则 json 包需要遵循这些指针,并在必要时分配值。如果 Person 中的字段被定义为**string.
type Person struct {
Name **string
Age *int
}
type People []*Person
http://play.golang.org/p/vLq0nJPG5M
TA贡献1775条经验 获得超11个赞
该json.Unmarshal实现考虑了多个间接性。检查来源here,特别是decodeState.indirect方法:
// indirect walks down v allocating pointers as needed,
// until it gets to a non-pointer.
// if it encounters an Unmarshaler, indirect stops and returns that.
// if decodingNull is true, indirect stops at the last pointer so it can be set to nil.
func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) {
// If v is a named type and is addressable,
// start with its address, so that if the type has pointer methods,
// we find them.
if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
v = v.Addr()
}
for {
if v.Kind() == reflect.Interface && !v.IsNil() {
e := v.Elem()
if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
v = e
continue
}
}
if v.Kind() != reflect.Ptr {
break
}
//and so on
}
return nil, nil, v
解组数组时调用相同的方法:
func (d *decodeState) array(v reflect.Value) {
u, ut, pv := d.indirect(v, false)
//...
那会让我相信 go 可以很好地处理双重间接。如果不出意外,json 包源代码是反射包全部内容的一个很好的例子。
简而言之,检查值,如果解码器正在处理指针,它将使用反射来计算有多少间接级别,并确定目标具有/是什么类型。从解码源开始的地方是这样的:func (d *decodeState) unmarshal(v interface{}) (err error) {从那一点开始,它是不言自明的。
TA贡献1820条经验 获得超9个赞
正如其他答案所说,遵循指示。
这个错误(零指针)有点奇怪,但当你考虑它时是有道理的。
package main
import (
"encoding/json"
"fmt"
"log"
)
type MyStruct struct {
A string `json:"a"`
}
func main() {
data := []byte(`{"a":"foo"}`)
var a *MyStruct
err := json.Unmarshal(data, a) // nil ptr
if err != nil {
log.Fatal(err)
}
fmt.Println(a)
}
但这不会出错(指向 nil 指针的指针)。
package main
import (
"encoding/json"
"fmt"
"log"
)
type MyStruct struct {
A string `json:"a"`
}
func main() {
data := []byte(`{"a":"foo"}`)
var a *MyStruct
err := json.Unmarshal(data, &a) // **MyStruct, ptr to nil ptr
if err != nil {
log.Fatal(err)
}
fmt.Println(a)
}
https://play.golang.org/p/eI8jqWZOmGW
- 3 回答
- 0 关注
- 223 浏览
添加回答
举报