反射

反射 #

使用反射 #

前提 #

使用反射之前必须引用包 reflect

定义一个结构及方法 #

import "reflect"

type User struct {
	Id   int
	Name string
	Age  int
}

func (u User) say() {
	fmt.Println("hello")
}
u := User{Id: 1, Name: "Peter", Age: 20}

反射所有字段及方法 #

  • reflect.TypeOf(o) 用于获得类型原型
  • reflect.ValueOf(o) 用于获得值

注意要想访问字段的值则字段应为 public,要想调用方法则方法应为 public

func info(o interface{}) {
	//获得参数类型的原型
	t := reflect.TypeOf(o)
	fmt.Println("t", t)                       //t main.User
	fmt.Println("t.Name()", t.Name())         //t.Name() User
	fmt.Println("t.NumField()", t.NumField()) //t.NumField() 3

	v := reflect.ValueOf(o)
	fmt.Println("v", v) //v <main.User Value>

	//检测类型
	if k := t.Kind(); k != reflect.Struct {
		return
	}

	//输出属性
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		//此时的 Field 必须为public
		val := v.Field(i).Interface()
		fmt.Println(f.Name, f.Type, val)
		//--> outputs
		//Id int 1
		//Name string Peter
		//Age int 20
	}
	fmt.Println()

	//输出方法
	for i := 0; i < t.NumMethod(); i++ {
		m := t.Method(i)
		fmt.Println(m.Name, m.Type)
		//-->outputs
		//say func(main.User)
	}
}
info(u)

访问结构中的匿名字段 #

type Manager struct {
	User
	title string
}
//type
m := Manager{title: "Manager", User: User{Id: 2, Name: "Jane", Age: 22}}
t := reflect.TypeOf(m)
f := t.FieldByIndex([]int{0, 1})
fmt.Println("f", f.Name, f.Type) //f Name string

//value
v := reflect.ValueOf(m)
val := v.FieldByIndex([]int{0, 1}).Interface()
fmt.Println("val", val) //val Jane

使用 reflect.FieldByIndex() 方法,该方法的参数为 slice,以上第一个位置的 “0” 表示 Manager 的0号属性(User),1表示 User 的1号属性(Name)

动态修改属性的值 #

func set(o interface{}) {
	v := reflect.ValueOf(o)
    ////判断是否为指针类型且可写
	if k := v.Kind(); k != reflect.Ptr || !v.Elem().CanSet() {
		fmt.Println("invalid type")
		return
	}
	v = v.Elem()
	f := v.FieldByName("Name")

	//判断指定属性是否存在
	if !f.IsValid() {
		fmt.Println("invalid name")
		return
	}
	if f.Kind() == reflect.String {
		f.SetString("a")
	}
}

u := User{Id: 1, Name: "Peter", Age: 20}
fmt.Println("u.Name", u.Name) //u.Name Peter
set(&u)
fmt.Println("u.Name", u.Name) //u.Name a
set(u)

注意以上是通过传入指针来实现动态修改的

动态调用方法 #

注意调用方法时该方法应为 public

func (u User) Hello(name string) {
	fmt.Println("hello ", name, " my name is ", u.Name)
}

u := User{Id: 1, Name: "Peter", Age: 20}
v = reflect.ValueOf(u)
mn := v.MethodByName("Hello")
args := []reflect.Value{reflect.ValueOf("Andy")}
mn.Call(args)
fmt.Println("u.Name", u.Name) //hello  Andy  my name is  a
沪ICP备17055033号-2