英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论