反射的应用-结构体类型转换
结构体类型转换#
与前面的测试类似的思路,将结构体类型 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)
}
推荐文章: