duanbei7005 2016-02-24 14:06
浏览 641
已采纳

json.Unmarshal()接受一个指向指针的指针

I noticed, quite by accident, that I can successfully pass both a pointer to a struct, and a pointer to a pointer to a struct to json.Unmarshal(), and both work just fine:

package main

import (
    "testing"
    "encoding/json"
)

type Person struct {
    Name string
    Age  int
}

func TestMarshaling(t *testing.T) {
    foo := &Person{Name: "bob", Age: 23}

    // marshal it to bytes
    b, err := json.Marshal(foo)
    if err != nil {
        t.Error(err)
    }

    bar := &Person{}             // pointer to new, empty struct
    err = json.Unmarshal(b, bar) // unmarshal to bar, which is a *Person
    if err != nil {
        t.Error(err)
    }
    testBob(t, bar)  // ok

    bar = &Person{}               // pointer to new, empty struct
    err = json.Unmarshal(b, &bar) // wait a minute, passing in a **Person, yet it still works?
    if err != nil {
        t.Error(err)
    }
    testBob(t, bar) // ok
}

func testBob(t *testing.T, person *Person) {
    if person.Name != "bob" || person.Age != 23 {
        t.Error("not equal")
    }
}

I was really surprised that the second one (unmarshal to **Person) worked.

What's going on in json.Unmarshal()? Is it dereferencing the pointers until it finds a struct?

The documentation offers:

To unmarshal JSON into a pointer, Unmarshal first handles the case of the JSON being the JSON literal null. In that case, Unmarshal sets the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into the value pointed at by the pointer

It seems to be doing a bit more than that. What's really going on?

Fleshing out my question more: how does it know to automatically dereference my pointer to a pointer? The documentation says it will unmarshal "into the value pointed at by the pointer". Since the value of my pointer is in fact another pointer, and has no Name/Age fields, I expected it to stop there.

To be clear: I'm not saying there's a bug or misfeature in Unmarshal(); I'm trying to satisfy my astonishment that it works at all when given a ptr-to-ptr, and avoid any potential pitfalls in my use of it.

  • 写回答

3条回答 默认 最新

  • dtgsl60240 2016-02-24 16:03
    关注

    The json package has no reason to "stop at a pointer", since a pointer means nothing in json. It has to keep walking the tree in order to find a value to write. Since the json package is going to allow unmarshaling the same value into Type or *Type, it stands to reason that it should be able to unmarshal that into **Type, which is also a valid type in Go.

    For a example, if Person were defined using pointers to differentiate between nil and zero values, and you were unmarshaling into a slice of []*Person, the json package needs to follow those pointers, and allocate values if necessary. The same applies if a field in Person were defined as a **string.

    type Person struct {
        Name **string
        Age  *int
    }
    
    type People []*Person
    

    http://play.golang.org/p/vLq0nJPG5M

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 电力市场出清matlab yalmip kkt 双层优化问题
  • ¥30 ros小车路径规划实现不了,如何解决?(操作系统-ubuntu)
  • ¥20 matlab yalmip kkt 双层优化问题
  • ¥15 如何在3D高斯飞溅的渲染的场景中获得一个可控的旋转物体
  • ¥88 实在没有想法,需要个思路
  • ¥15 MATLAB报错输入参数太多
  • ¥15 python中合并修改日期相同的CSV文件并按照修改日期的名字命名文件
  • ¥15 有赏,i卡绘世画不出
  • ¥15 如何用stata画出文献中常见的安慰剂检验图
  • ¥15 c语言链表结构体数据插入