golang学习笔记(反射)

反射
Go语言中的反射是由 reflect 包提供支持的,它定义了两个重要的类型 Type 和 Value 任意接口值在反射中都可以理解为由 reflect.Typereflect.Value 两部分组成,并且 reflect 包提供了 reflect.TypeOf 和 reflect.ValueOf 两个函数来获取任意对象的 Value 和 Type。

获取类型和name

m := Monster{
		Name:"玉兔精",
		Age:20,
		Sal: 888.9,
		Sex: "female",
	}
	data, err := json.Marshal(m)
	if err == nil {
		fmt.Println(string(data))
	}else{
		fmt.Println("nil")
	}

	typeM := reflect.TypeOf(m)
	fmt.Println(typeM,typeM.Kind(),typeM.Name())//struct,Monster


	type Enum int
	const(
		num Enum	 = 0
	)
	typeCons := reflect.TypeOf(num)
	fmt.Println(typeCons.Kind(),typeCons.Name())//int,Enum
	ins := &Monster{
		Name:"玉兔精",
		Age:20,
		Sal: 888.9,
		Sex: "female",
	}
	//对于指针变量,则需要通过Elem() 方法获取
	fmt.Println((reflect.TypeOf(ins)).Elem().Name())//Master
	fmt.Println((reflect.TypeOf(ins)).Elem().Kind())//strcurt

获取结构体成员信息

func main() {
	type cat struct {
		Name string
		Type int `json:"type" id:"100"`
	}
	ins := cat{
		Name: "mimi",
		Type: 1,
	}
	tyoeOfCat := reflect.TypeOf(ins)
	//遍历结构体所有成员
	for i := 0; i < tyoeOfCat.NumField(); i++ {
		filedType := tyoeOfCat.Field(i)
		fmt.Println(filedType.Name+"\n标签:",filedType.Tag)
	}
	//通过字段名获取字段类型信息
	if catType, ok := tyoeOfCat.FieldByName("Type");ok{
		fmt.Println(catType.Tag.Get("json"),catType.Tag.Get("id"))
	}
}

结构体标签(Struct Tag)
Tag 在结构体字段后方书写的格式如下:
key1:"value1" key2:"value2"

反射三定律

1. 反射可以将“接口类型变量”转换为“反射类型对象”
2. 反射可以将“反射类型对象”转换为“接口类型变量”
3. 如果要修改反射类型对象,其值必须是“addressable”

反射调用函数

func foo(v int)(int,int)  {
	return v+10,v-10

}
func main()  {
	//fmt.Println(foo(1))

	v := reflect.ValueOf(foo)
	call := v.Call([]reflect.Value{reflect.ValueOf(2)})
	fmt.Println(call[0],call[1])
}

反射判断零值空指

var a *int
	fmt.Println(reflect.ValueOf(a).IsNil())//true
	var b *int = new(int)
	fmt.Println(reflect.ValueOf(b).IsNil())//false

	var c int
	fmt.Println(reflect.ValueOf(c).IsZero())//true
	c = 10
	fmt.Println(reflect.ValueOf(c).IsZero())//false
	s := struct {

	}{}
	fmt.Println(reflect.ValueOf(s).FieldByName("hello").IsValid())

	m := make(map[interface{}]interface{})
	m[3]="hello"
	fmt.Println(reflect.ValueOf(m).MapIndex(reflect.ValueOf(3)).IsValid())

可用 reflect.Value 的 CanAddr 方法来判断其是否可以被取地址:
golang学习笔记(反射)_第1张图片
golang学习笔记(反射)_第2张图片

将结构体转成map

func ToMap(in interface{},tagName string) (map[string]interface{},error){
	out := make(map[string]interface{})

	v:=reflect.ValueOf(in)

	if v.Kind() == reflect.Ptr {//指针类型
		v = v.Elem()
	}
	if v.Kind() != reflect.Struct {//非结构体返回错误提示
		return nil,fmt.Errorf("Tomap only accept strcut or struct pointer:got %T",v)
	}
	t := v.Type()

	for i := 0; i < v.NumField(); i++ {
		fi := t.Field(i)
		if tagValue := fi.Tag.Get(tagName);tagValue != "" {
			out[tagValue] = v.Field(i).Interface()
		}
	}
	return out,nil

}

func main()  {
	type UserInfo struct {
		Name string `json:"name"`
		Age int `json:"age"`
	}
	user := UserInfo{
		Name: "奇衡三",
		Age: 18,
	}
	toMap, _ := ToMap(user, "json")

	fmt.Println(toMap)
}

你可能感兴趣的:(golang,golang,反射,json,指针)