【问题标题】:Pointer receiver confusion指针接收器混淆
【发布时间】:2015-08-28 18:07:46
【问题描述】:

我对以下代码的行为感到困惑。 playground

var foo json.RawMessage
_ = json.Unmarshal([]byte(`{ "zoo": 123 }`), &foo)

enc := json.NewEncoder(os.Stdout)

// Works as expected
_ = enc.Encode(struct{ Foo *json.RawMessage }{&foo})

// MarshalJSON has a pointer reciever, so it doesn't get invoked here
_ = enc.Encode(struct{ Foo json.RawMessage }{foo})

// How is MarshalJSON being invoked if .Foo is not a pointer?
_ = enc.Encode(&struct{ Foo json.RawMessage }{foo})

输出:

{"Foo":{"zoo":123}}
{"Foo":"eyAiem9vIjogMTIzIH0="}
{"Foo":{"zoo":123}}

我不明白为什么对json.Encoder.Encode 的第三次调用能够访问json.RawMessage.MarshalJSON,即使它不是指针。

【问题讨论】:

标签: go


【解决方案1】:

在任何addressable value 上调用方法时,Go 将自动引用该值以使用指针接收器调用方法。

type Foo struct{}
func (f *Foo) Call() {}

// f isn't a pointer, but is addressable
f := Foo{}
f.Call()

此外,如果非指针值在可寻址结构中,它也可以作为需要指针接收器的方法的引用。

type Bar struct {
    Foo Foo
}

// b is addressable, therefor so is b.Foo
b := Bar{
    Foo: f,
}
b.Foo.Call()

您的最后一个示例使用外部结构的地址来获取 Foo 字段的地址,并调用MarshalJSON

【讨论】:

  • 在第二个例子中,结构体字面量是在堆栈上创建的,然后被复制到Encodes 堆栈帧中。为什么它不被认为是“可寻址的”?堆栈上的值是可寻址的。
  • @iliacholy:它是否在堆栈上与可寻址性规范无关,但在第二个示例中,结构文字的 copy 分配在@987654326 @ 堆栈中的参数。接口中的值不可寻址。
猜你喜欢
  • 2017-11-30
  • 1970-01-01
  • 2021-04-04
  • 1970-01-01
  • 2010-09-25
  • 2011-09-04
  • 2016-11-08
  • 2012-10-15
相关资源
最近更新 更多