反射
Go语言中的反射是由 reflect 包提供支持的,它定义了两个重要的类型 Type 和 Value 任意接口值在反射中都可以理解为由 reflect.Type 和 reflect.Value 两部分组成,并且 reflect 包提供了 reflect.TypeOf 和 reflect.ValueOf 两个函数来获取任意对象的 Value 和 Type。
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 方法来判断其是否可以被取地址:
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)
}