golang中的标准库反射

反射

反射是指程序在运行期对程序本身访问和修改的能力

变量的内在机制

变量包含类型信息和值信息 var arr [10]int arr[0] = 10
类型信息:是静态的元信息,是预先定义好的
值信息:是程序运行过程中动态改变的

反射的使用

reflect包封装了反射相关的方法
获取类型信息:reflect.TypeOf,是静态的
获取值信息:reflect.ValueOf,是动态的

空接口和反射

反射可以在运行时动态获取程序的各种详细信息
反射获取interface类型信息

  1. 反射获取interface类型信息
func main() {
	var x = math.Pi
	reflectType(x)
}

func reflectType(tmp interface{}) {
	t := reflect.TypeOf(tmp)
	fmt.Println("类型是:", t)

	// Kind()可以获取具体类型
	k := t.Kind()
	fmt.Println(k)

	switch k {
	case reflect.Float64:
		fmt.Println("Float64类型")
	case reflect.String:
		fmt.Println("String类型")
	}

}
  1. 反射获取interface的值信息
func main() {
	var x = math.Pi
	reflectValue(x)
}

func reflectValue(tmp interface{}) {
	fmt.Printf("%v: %T\n", tmp, tmp)
	v := reflect.ValueOf(tmp)
	fmt.Println(v)

	// 获取到v的具体类型
	k := v.Kind()
	fmt.Println(k)

	switch k {
	case reflect.Float64:
		fmt.Println("float64类型")
	}
}
  1. 反射修改值信息
func main() {
	var x = math.Pi
	// 反射修改值需要传递指针类型,不是float类型
	reflectSetValue(&x)
	fmt.Println("main: ", x)
}

func reflectSetValue(tmp interface{}) {
	v := reflect.ValueOf(tmp)
	k := v.Kind()  // Kind() 获取具体类型
	switch k {
	case reflect.Float64:
		// 反射修改值
		v.SetFloat(15)
		fmt.Println("tmp is", v.Float())
	case reflect.Ptr:
		// Elem获取地址指向的值
		v.Elem().SetFloat(18)
		fmt.Println("tmp is", v.Elem().Float())
		fmt.Println(v.Pointer())
	}
}

结构体与反射

  1. 查看类型、字段和方法
点击查看代码
type User struct {
	Id int
	Name string
	Age int
}
func (u User) Hello() {
	fmt.Println("Hello")
}

func main() {
	u := User{11, "zhang", 18}
	Poni(u)
}

func Poni(o interface{}) {
	t := reflect.TypeOf(o)
	fmt.Println("类型是:", t)  // 类型是: main.User
	fmt.Println(t.Name())  // User

	v := reflect.ValueOf(o)
	fmt.Println("值是:", v)  // 值是: {11 zhang 18}

	// 获取所有属性
	// t.NumField 可以获取字段数量
	for i := 0; i < t.NumField(); i++ {
		// 获取每个字段
		f := t.Field(i)
		fmt.Println(f.Name, f.Type)

		// 获取字段的值信息
		val := v.Field(i).Interface()  // Interface()获取字段对应的值
		fmt.Println(val)
	}

	fmt.Println("==========方法===========")
	for i := 0; i < t.NumMethod(); i++ {
		m := t.Method(i)
		fmt.Println(m.Name, m.Type)
	}
}
  1. 查看匿名字段
点击查看代码
type User struct {
	Id int
	Name string
	Age int
}
type Boy struct {
	User
	Addr string
}

func main() {
	b := Boy{User{11, "zhang", 18}, "北京市"}
	t := reflect.TypeOf(b)
	fmt.Println(t)  // main.Boy

	// 匿名:Anonymous
	fmt.Printf("%#v\n", t.Field(0))
	// 输出:reflect.StructField{Name:"User", PkgPath:"", Type:(*reflect.rtype)(0x3de280), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:true}

	// 值信息
	fmt.Printf("%#v\n", reflect.ValueOf(b).Field(0))
}
  1. 修改结构体的值
点击查看代码
type User struct {
	Id int
	Name string
	Age int
}

func main() {
	u := User{11, "zhang", 18}
	setValue(&u)
	fmt.Println("main:", u)
}

// 修改结构体指向的值
func setValue(o interface{}) {
	v := reflect.ValueOf(o)
	// 获取指针指向的元素
	v = v.Elem()
	// 获取字段
	f := v.FieldByName("Name")
	if f.Kind() == reflect.String {
		f.SetString("哈哈哈")
	}
}
  1. 调用方法
点击查看代码
type User struct {
	Id int
	Name string
	Age int
}
func (User) Hello(name string) {
	fmt.Println("hello: ", name)
}

func main() {
	u := User{11, "lisi", 88}
	v := reflect.ValueOf(u)
	// 获取方法
	m := v.MethodByName("Hello")
	// 构建一些参数
	args := []reflect.Value{reflect.ValueOf("6666")}
	// 没参数的情况下:var args2 []reflect.Value
	// 调用方法,需要传入方法的参数
	m.Call(args)
}
  1. 获取字段的tag
type Student struct {
	Name string `json:"name1" db:"name2"`
}

func main() {
	s := Student{Name: "lisi"}
	v := reflect.ValueOf(&s)  
	// 注意:如果使用结构体指针,t.Elem()需要获取指针对应的值,如果使用的是s结构体,那么不需要t.Elem(),直接t.Field即可
	// 类型
	t := v.Type()
	// 获取字段
	f := t.Elem().Field(0)
	fmt.Println(f.Tag.Get("json"))
	fmt.Println(f.Tag.Get("db"))
}

posted @ 2021-12-06 18:07  专职  阅读(36)  评论(0编辑  收藏  举报