Golang Go语言中无法通过反射将 interface{} 转换成结构体的问题
最近写了个小 demo ,实现通过反射将结构体数组,转换成结构实现的接口类型的数组,到这部分没有问题。但是当打算从接口数组转换回结构结构体数组的时候,却转换失败,不知道原因是什么
代码见 https://go.dev/play/p/ajYUDEs6ssQ
如果不是通过反射,是可以通过类型断言将接口类型转换成底层的结构体,因为 go 的接口类型保存有底层结构的类型信息,但是通过反射却无法转换。
本来打算看看 go 反射的底层实现找找原因,但是水平有限没找到……有大手子可以帮忙解解惑吗?
Golang Go语言中无法通过反射将 interface{} 转换成结构体的问题
更多关于Golang Go语言中无法通过反射将 interface{} 转换成结构体的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
因为转换成 Stringer 的时候 box 了一次,底层类型变成了 interface 类型。
加个检查,对 interface 解包
if fe.Kind() == reflect.Interface {
fe = fe.Elem()
}
更多关于Golang Go语言中无法通过反射将 interface{} 转换成结构体的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
reflect.Value.Convert 支持 interface -> interface, 具体类型 -> interface 的转换, 不支持 interface 的转换
可以将 te.Set(fe.Convert(te.Type())) 修改为 te.Set(reflect.ValueOf(fe.Interface())), 这样就可以过了
不支持 interface -> 具体类型的转换, 补充一下
可以理解为,当Data 传给 reflect.ValueOf 时,做了Data->interface{}的转换,然后 convert 函数里,做的是 interface{} -> fmt.Stringer 的转换。这样 fmt.Stringer 的底层类型就变成了 interfaces{},*Data 的信息是包在了 interface{}里,fmt.Stringer 中是没法直接获取到?
哪里可以了解下为什么会有不支持 interface -> 具体类型转换?是 go 的类型系统设计的原因吗?
fmt.Printf("%+v", ss) 可以看出,你两个值是 Nil
#6 哦不是,我的问题
#5
reflect/values.go
if implements(dst, src) {
if src.Kind() == Interface {
return cvtI2I
}
return cvtT2I
}
reflect/types.go
// implements reports whether the type V implements the interface type T.
func implements(T, V *rtype) bool {
if T.Kind() != Interface {
return false
}
…
}
我猜测是这样的,Convert 的时候两个 Type 进行转换,前者是 fmt.Stringer 后者是 Data, Data => fmt.Stringer 可以因为实现了接口,但 fmt.Stringer => Data 不行, 如果两个被 Interface 抹掉了类型就会取 ValueType, 那两个底层 ValueType 都是 *Data 所以可以
原理上面已经说的差不多了,提醒下范型已经发布可用了,op 这个 demo 正好就是范型的用处
interface 是一个 fat pointer ,一个指向值,一个指向类型。正常情况下你把某个类型赋值给 interface (隐式 box )、或把一个 interface 转换成另一个 interface 是不会改变它的具体值和类型的。而 reflect.ValueOf 则是把一个 interface 里的值拿出来,并提供一些 API 。
但是你 Convert 的时候把一个具体类型转换成 interface ,这里是对其进行了一次原地打包的。
转换前:
( Data 值,Data 类型)
转换后:
( Stringer 值,Stringer 类型)
其中 Stringer 值为 ( Data 值,Data 类型)
确实这个老问题用泛型解决正好,已经准备将项目最低的版本设置为 1.18 了