反射有两种类型 reflect.Value 和 reflect.Type ,分别表示变量的值和类型,并且提供了两个函数 reflect.ValueOf 和 reflect.TypeOf 分别获取任意对象的 reflect.Value 和 reflect.Type。
reflect.Value 可以通过函数 reflect.ValueOf 获得。reflect.Value 被定义为一个 struct 结构体:
type Value struct {
typ *rtype
ptr unsafe.Pointer
flag
}
typ: 用于保存值的类型信息。在 Go 的 reflect 包中,rtype 结构表示类型信息。
ptr: 用于保存数据的指针或指向数据的指针。如果 flagIndir 标志被设置,ptr 就是指向数据的指针;否则,ptr 就是数据的指针。
flag: 用于保存与值相关的元信息和标志位。flag 的最低的几位用于表示标志位,其余的位用于存储类型的信息和其他元数据。flag 的位域包括:
可以看到,这个结构体中的字段都是私有的,我们只能使用 reflect.Value 的方法,部分方法比如有:
方法分为三类:
func main() {
i := 5
//int to reflect.Value
iv:=reflect.ValueOf(i)
//reflect.Value to int
i1 := iv.Interface().(int)
fmt.Println(i1)
}
//运行结果:
5
func main() {
i := 5
ipv := reflect.ValueOf(&i)
ipv.Elem().SetInt(6)
fmt.Println(i)
}
//运行结果:
6
func main() {
p := person{Name: "微客鸟窝",Age: 18}
pv:=reflect.ValueOf(&p)
pv.Elem().Field(0).SetString("无尘")
fmt.Println(p)
}
type person struct {
Name string
Age int
}
//运行结果:
{无尘 18}
步骤总结:
通过反射修改一个值的规则:
可被寻址,通俗地讲就是要向 reflect.ValueOf 函数传递一个指针作为参数。
如果要修改 struct 结构体字段值的话,该字段需要是可导出的,而不是私有的,也就是该字段的首字母为大写。
记得使用 Elem 方法获得指针指向的值,这样才能调用 Set 系列方法进行修改。
因为我们可以通过 type 关键字来自定义一些新的类型,而底层类型就是一些基础类型。比如上面示例中的 p 变量类型为 person,底层类型为 struct 结构体类型。
type person struct {
Name string
Age int
}
func main() {
p := person{Name: "微客鸟窝", Age: 18}
p1 := reflect.ValueOf(p)
p2 := reflect.ValueOf(&p)
fmt.Println(p1.Kind())
fmt.Println(p2.Kind())
}
//运行结果:
struct
ptr
Kind 方法返回一个 Kind 类型的值,它是一个常量,从源码看下定义的 Kind 常量列表,含了 Go 语言的所有底层类型:
一共 26 种,我们可以分类如下:
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int
Address string
}
func main() {
p := Person{"Alice", 30, "123 Main St"}
// 使用 reflect.ValueOf 获取结构体实例的反射值
pValue := reflect.ValueOf(p)
// 获取结构体字段的个数
numFields := pValue.NumField()
fmt.Println("Number of fields:", numFields)
// 遍历结构体的字段
for i := 0; i < numFields; i++ {
// 获取第 i 个字段的反射值
fieldValue := pValue.Field(i)
// 输出字段名和值
fieldName := pValue.Type().Field(i).Name
fmt.Printf("Field %s: %v\n", fieldName, fieldValue.Interface())
}
}
//输出结果
Number of fields: 3
Field Name: Alice
Field Age: 30
Field Address: 123 Main St