反射的应用-结构体类型转换
结构体类型转换
与前面的测试类似的思路,将结构体类型Student转成Interface,再获取其reflect.Type类型和reflect.Value类型。结合Value的方法使用变量,最后将reflect.Value类型转成 interface,再通过类型断言,转成原始的Student类型。
主要体会“断言”在转换过程中的重要性。
type Student struct {
Id int
Name string
Age int
}
func reflectTest(i interface{}) {
// 获取变量的 reflect.Type
reType := reflect.TypeOf(i)
fmt.Println("reflect.Type=", reType)
// 获取变量的 reflect.Value
reVal := reflect.ValueOf(i)
fmt.Println("reflect.Value=", reVal)
// 打印reVal类型,使用 reVal,打印Name 成员 失败。无法索引Name成员
//fmt.Printf("reVal=%T, name=%v",reVal, reVal.Name)
// 将 reVal 转成 interface
iVal := reVal.Interface()
fmt.Printf("iVal= %v, type= %T\n", iVal, iVal)
// iVal.Name 会报错Unresolved reference 'Name'
// fmt.Printf("iVal= %v, type= %T, name= %v\n", iVal, iVal, iVal.Name)
// 将 interface 通过类型断言 转回成 Student
// stu:= iVal.(Student)
if stu, ok := iVal.(Student); ok {
fmt.Printf("stu= %v, type= %T, name=%v\n", stu, stu, stu.Name)
}
}
func main() {
// 创建一个结构体对象
stu := Student{9527, "Andy", 18}
// 调用反射测试函数
reflectTest(stu)
}
与int类型类似的,reflect.ValueOf(i) 返回的reVal 的值打印是结构体的成员信息。而使用fmt.Printf() 的%T 去查看reVal 的类型,发现它依然是reflect.Value类型。因此,是不能直接使用 reVal 去索引它的成员 Name的。使用iVal := reVal.Interface(),将其转换为interface。可以索引Name吗?依然不行,会显示错误:Unresolved reference 'Name'
这里强调!反射的本质是运行时进行调动的一种机制。虽然运行时,iVal的的确确是一个Student 结构体对应的类型,但编译时,编译器失无法确认的。
因此!必须使用类型断言!!转成具体类型,才能索引成员变量Name。
// 将 interface 通过类型断言 转回成 Student
stu := iVal.(Student)
fmt.Printf("stu= %v, type= %T, name= %v\n", stu, stu, stu.Name)
输出结果:stu= {9527 Andy 18}, type= main.Student, name= Andy
当然,为了确保断言成功,我们可以添加判断机制:
// 将 interface 通过类型断言 转回成 Student
//stu:= iVal.(Student)
if stu, ok := iVal.(Student); ok {
fmt.Printf("stu= %v, type= %T, name= %v\n", stu, stu, stu.Name)
}