为啥在 Go 中将指针放入 interface 会导致反射丢失类型的名称?

Posted

技术标签:

【中文标题】为啥在 Go 中将指针放入 interface 会导致反射丢失类型的名称?【英文标题】:Why does putting a pointer in an interface in Go cause reflect to lose the name of the type?为什么在 Go 中将指针放入 interface 会导致反射丢失类型的名称? 【发布时间】:2015-04-04 23:47:48 【问题描述】:

下面的示例显示了当您反映设置为对象 (g) 和指向该对象 (h) 的指针的接口 时会发生什么。这是设计使然,我应该期望我的数据类型丢失还是当我将指针放在接口 中时我无法取回数据类型的名称?

包主 导入“fmt” 导入“反射” 类型 Foo 结构 条弦 功能主要() f := FooBar: "FooBar" typeName := reflect.TypeOf(f).Name() fmt.Printf("typeName %v\n", typeName) 变量 g 接口 g = f typeName = reflect.TypeOf(g).Name() fmt.Printf("typeName %v\n", typeName) var h 接口 h = &f typeName = reflect.TypeOf(h).Name() fmt.Printf("typeName %v\n", typeName)

输出:

类型名称 Foo 类型名称 Foo 类型名称

也位于:

http://play.golang.org/p/2QuBoDxHfX

【问题讨论】:

【参考方案1】:

正如Name 方法的文档所说,未命名的类型将返回一个空字符串:

Name 在其包中返回类型的名称。 它为未命名的类型返回一个空字符串。

h的类型是一个未命名的指针类型,它的元素类型是命名的struct类型Foo

v := reflect.TypeOf(h)
fmt.Println(v.Elem().Name()) // prints "Foo"

如果您想要这样的复杂未命名类型的标识符,请使用String 方法:

fmt.Println(v.String()) // prints "*main.Foo"

【讨论】:

谢谢!。非常有意思。阅读 Elem() 上的文档有点令人困惑。 // Elem 返回一个类型的元素类型。 // 如果类型的 Kind 不是 Array、Chan、Map、Ptr 或 Slice,它会发生混乱。 Elem() 类型。所以,reflect.TypeOf 返回一个 Type,Elem 返回一个 elements Type。 “元素”是我所反映的价值吗? 另外,似乎 Elem() 没有恐慌的唯一原因是因为包含的类型是一个指针。我觉得有趣的是 Elem().Name() 然后返回“Foo”而不是 *Foo。 @Nate:Elem 这个名字对于指针来说有点误导,但对于其他类型来说是完全合理的。例如。如果您考虑[]intElem() 方法会为您提供切片元素的类型,这里是 int(而不是 []int)。相同的逻辑适用于指针:您反映指针类型,Elem() 为您提供“指针类型的元素”的类型,并且 Name 显然是“Foo”而不是“*Foo”作为元素的名称[]int 是 int 而不是 []int。 不管怎样,h 的类型是interface,而不是指针类型。 h 具有(未命名的)指针类型。如果您将&h 传递给reflect.TypeOf 而不是h,这将变得很明显。但是,在 Go 中,接口(大部分)是按值传递的,reflect.TypeOf 采用 interface,因此如果按值传递,它无法知道 h 的类型。这种区别在这里不是很重要,但如果h 有一个命名接口类型,如io.Reader,就会更加明显。

以上是关于为啥在 Go 中将指针放入 interface 会导致反射丢失类型的名称?的主要内容,如果未能解决你的问题,请参考以下文章

go 指针(interface{},map)

go语言-interface的值接收和指针接受的区别

go语言-interface的值接收和指针接受的区别

go语言-interface的值接收和指针接受的区别

技巧:Go 结构体如何转换成 map[string]interface{}

如何在 django 中将 api 放入 celery 任务中?