Golang中关于接口和指向接口的指针的反射

huangapple go评论89阅读模式
英文:

Golang reflection on interface vs pointer-to-interface

问题

在gob使用示例http://golang.org/src/encoding/gob/example_interface_test.go中,他们提供了以下论点:
“将指针传递给接口,这样Encode就可以看到(因此发送)接口类型的值。如果我们直接传递p,它将看到具体类型。请参阅博文“反射定律”以了解背景。”

我已经两次阅读了《反射定律》,还阅读了相关的Russ Cox文章。但我找不到指针接口和接口之间的区别。

那么为什么通过指针传递它可以看到接口类型的值,而没有指针时它会看到(对我来说令人惊讶的)具体类型呢?

英文:

In the example of gob usage http://golang.org/src/encoding/gob/example_interface_test.go they provide the following thesis:
Pass pointer to interface so Encode sees (and hence sends) a value of interface type. If we passed p directly it would see the concrete type instead. See the blog post, "The Laws of Reflection" for background.

I've read The Laws of reflection twice, and a related Russ Cox article too. But I can't find a distinction between pointer-to-interface and interface there.

So why is it that through the pointer it sees a value of interface type, and with no pointer it sees (surprisingly to me) the concrete type?

答案1

得分: 5

我觉得相关的部分是这样的:这里

继续下面的内容:

var empty interface{}
empty = w

我们的空接口值empty将再次包含相同的对(tty, *os.File)。这很方便:空接口可以保存任何值,并且包含了我们可能需要的关于该值的所有信息。

当你将一个接口值赋给类型为interface{}的值时,新值的"数据指针"部分并不指向旧值,而是指向旧值所指向的数据。我们可以通过一些unsafe代码来证明这一点:

type iface struct {
    Type, Data unsafe.Pointer
}

var r io.Reader = &bytes.Buffer{}
var i interface{} = r

rr := *(*iface)(unsafe.Pointer(&r))
ii := *(*iface)(unsafe.Pointer(&i))

fmt.Printf("%v\n", ii.Data == rr.Data) // 输出 true

另一方面,如果我们使用指针,它将指向接口值本身。因此,reflect现在可以准确地看到我们所讨论的接口是什么。例如:

var i2 interface{} = &r
ii2 := *(*iface)(unsafe.Pointer(&i2))
fmt.Printf("%v\n", ii2.Data == unsafe.Pointer(&r)) // 输出 true

Playground: http://play.golang.org/p/0ZEMdIFhIj

英文:

It seems to me that the relevant part is this:

>Continuing, we can do this:
>
var empty interface{}
empty = w

>*and our empty interface value empty will again contain that same pair, (tty, os.File). That's handy: an empty interface can hold any value and contains all the information we could ever need about that value.

(emphasis added)

When you assign an interface value to a value of type interface{}, the "pointer to data" part of the new value doesn't point to the old value, but rather to the data old value was pointing to. We can prove that with a bit of unsafe code:

type iface struct {
	Type, Data unsafe.Pointer
}

var r io.Reader = &bytes.Buffer{}
var i interface{} = r

rr := *(*iface)(unsafe.Pointer(&r))
ii := *(*iface)(unsafe.Pointer(&i))

fmt.Printf("%v\n", ii.Data == rr.Data) // Prints true.

On the other hand, if we use a pointer, it will point to the interface value itself. So now reflect can actually see, what interface exactly are we talking about. E.g.:

var i2 interface{} = &r
ii2 := *(*iface)(unsafe.Pointer(&i2))
fmt.Printf("%v\n", ii2.Data == unsafe.Pointer(&r)) // Prints true.

Playground: http://play.golang.org/p/0ZEMdIFhIj

huangapple
  • 本文由 发表于 2015年4月30日 23:09:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/29971363.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定