Name and Kind
typeOfCat := reflect.TypeOf(cat{})
typeOfCat.Name() // cat
typeOfCat.Kind() // struct
typeOfCat.NumField() // 2 几个字段
typeOfCat.Field(i) //第几个字段
typeOfCat.FieldByName("Type") // 找名为Type的字段
typeOfCat.MethodByName("Start") // 找名为Start的方法
if typeofCat.Kind() == "ptr"{
res := typeOfCat.Elem() // 等价于*ptr
res.Name()
res.Kind()
}
reflect.ValueOf()和reflect.Value
valueOfA := reflect.ValueOf(a)
var getA int = valueOfA.Interface().(int)
var getA2 int = int(valueOfA.Int())
通过反射获取值信息
使用反射值对象包装任意值
Go语言中,使用 reflect.ValueOf() 函数获得值的反射值对象(reflect.Value)。书写格式如下:
value := reflect.ValueOf(rawValue)
reflect.ValueOf 返回 reflect.Value 类型,包含有 rawValue 的值信息。reflect.Value 与原值间可以通过值包装和值获取互相转化。reflect.Value 是一些反射操作的重要类型,如反射调用函数。
从反射值对象获取被包装的值
Go语言中可以通过 reflect.Value 重新获得原始值。
1) 从反射值对象(reflect.Value)中获取值的方法
可以通过下面几种方法从反射值对象 reflect.Value 中获取原值,如下表所示。
方法名 | 说 明 |
---|---|
Interface() interface {} | 将值以 interface{} 类型返回,可以通过类型断言转换为指定类型 |
Int() int64 | 将值以 int 类型返回,所有有符号整型均可以此方式返回 |
Uint() uint64 | 将值以 uint 类型返回,所有无符号整型均可以此方式返回 |
Float() float64 | 将值以双精度(float64)类型返回,所有浮点数(float32、float64)均可以此方式返回 |
Bool() bool | 将值以 bool 类型返回 |
Bytes() []bytes | 将值以字节数组 []bytes 类型返回 |
String() string | 将值以字符串类型返回 |
2) 从反射值对象(reflect.Value)中获取值的例子
下面代码中,将整型变量中的值使用 reflect.Value 获取反射值对象(reflect.Value)。再通过 reflect.Value 的 Interface() 方法获得 interface{} 类型的原值,通过 int 类型对应的 reflect.Value 的 Int() 方法获得整型值。
package main
import (
"fmt"
"reflect"
)
func main() {
// 声明整型变量a并赋初值
var a int = 1024
// 获取变量a的反射值对象
valueOfA := reflect.ValueOf(a)
// 获取interface{}类型的值, 通过类型断言转换
var getA int = valueOfA.Interface().(int)
// 获取64位的值, 强制类型转换为int类型
var getA2 int = int(valueOfA.Int())
fmt.Println(getA, getA2)
}
代码输出如下:
1024 1024
通过reflect反射修改值
判断反射值是否可以修改?CanSet(),是否能被取址CanAddr()
结构体成员中,如果字段没有被导出,即便不使用反射也可以被访问,但不能通过反射修改
-
指针指向的具体元素
x := 1 v := reflect.ValueOf(&x) v = v.Elem()
-
slice的元素
s := []int{1,1} v := reflect.ValueOf(s) e := v.Index(0)
-
可寻址的结构体的字段(指向结构体的指针)
type Orange struct{ Size int } a := Orange{99} v := reflect.ValueOf(&a) v = v.Elem() field = v.FieldByName("field")
-
可寻址的数组的元素(指向数组的指针)
a := [2]int{1,1} v := reflect.ValueOf(&a) v = v.Elem() vIndex = v.Index(0) vIndex.SetInt(1) vIndex.SetInt(1)
Set(x Value) | 将值设置为传入的反射值对象的值 |
---|---|
Setlnt(x int64) | 使用 int64 设置值。当值的类型不是 int、int8、int16、 int32、int64 时会发生宕机 |
SetUint(x uint64) | 使用 uint64 设置值。当值的类型不是 uint、uint8、uint16、uint32、uint64 时会发生宕机 |
SetFloat(x float64) | 使用 float64 设置值。当值的类型不是 float32、float64 时会发生宕机 |
SetBool(x bool) | 使用 bool 设置值。当值的类型不是 bod 时会发生宕机 |
SetBytes(x []byte) | 设置字节数组 []bytes值。当值的类型不是 []byte 时会发生宕机 |
SetString(x string) | 设置字符串值。当值的类型不是 string 时会发生宕机 |
通过类型信息创建实例
var a int
typeOfA := reflect.TypeOf(a)
aIns := reflect.New(typeOfA) // 等价于 new(int)
fmt.Println(aIns.Type(), aIns.Kind())
Go语言结构体标签(Struct Tag)
结构体标签的格式
tag 格式:json:"type" id:"100"
注意:
- key:“value” 冒号后没有空格
- 两个key之间,一个空格,多一个都不行
type cat struct{
Name string
Type int `json:"type" id:"100"`
}
从结构体标签中获取值
typeOfCat := reflect.TypeOf(cat{})
catType = typeOfCat.FieldByName("Type")
catType.Tag.Get("json")
常见用法
动态调用函数(无参数)
- 直接
reflect.Valueof
MethodByName
- 调用
Call
方法
type T struct {}
func main() {
name := "Do"
t := &T{}
reflect.ValueOf(t).MethodByName(name).Call(nil)
}
func (t *T) Do() {
fmt.Println("hello")
}
动态调用函数(有参数)
- 创建
reflect.Value
切片 reflect.Valueof(t).MethodByName(string)
调用Call方法传入参数
type T struct{}
func main() {
name := "Do"
t := &T{}
a := reflect.ValueOf(1111)
b := reflect.ValueOf("world")
in := []reflect.Value{a, b}
reflect.ValueOf(t).MethodByName(name).Call(in)
}
func (t *T) Do(a int, b string) {
fmt.Println("hello" + b, a)
}
接收返回值
- 返回
[]reflect.Value
- 调用
Interface()
方法,转为interface{}
类型 - 断言类型
type T struct{}
func main() {
name := "Do"
t := &T{}
ret := reflect.ValueOf(t).MethodByName(name).Call(nil)
fmt.Printf("strValue: %[1]v\nerrValue: %[2]v\nstrType: %[1]T\nerrType: %[2]T", ret[0], ret[1].Interface().(error))
}
func (t *T) Do() (string, error) {
return "hello", errors.New("new error")
}
Tag解析
reflect.Typeof
有NumField
,Field根据序号索取,取其中的tag
type T struct{
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
a := T{}
tt := reflect.TypeOf(a)
for i:=0;i<tt.NumField();i++{
fmt.Println(tt.Field(i).Name)
fmt.Println(tt.Field(i).Tag.Get("json"))
fmt.Println(tt.Field(i).Tag.Lookup("json"))
fmt.Println(tt.Field(i).Type)
}
}
通过kind()处理不同分支
reflect.Typeof().Kind()
func main() {
t := 1
a := reflect.TypeOf(t)
switch a.Kind() {
case reflect.String:
fmt.Println("string")
case reflect.Int:
fmt.Println("int")
default:
fmt.Println("default")
}
}
判断结构体是否实现接口
- 将
nil
强转为接口指针类型,通过reflect.Typeof().Elem
获取其接口类型 reflect.Typeof
调用方法Implements
来判断
type IT interface {
test1()
}
type T struct {
A string
}
func (t *T) test1() {}
func main() {
t := &T{}
elem := reflect.TypeOf((*IT)(nil)).Elem()
if reflect.TypeOf(t).Implements(elem) {
fmt.Println("OK")
}
}
直接通过接口强转判断
- 将类型转换为
reflect.Value
- 将
reflect.Value
调用Interface()方法转为接口类型 - 类型断言
type ITester interface {
test1()
}
type User struct {
A string
}
func main() {
u := &User{}
v := reflect.ValueOf(u)
val, ok := v.Interface().(ITester)
if ok {
fmt.Println("Support Interface", val)
}
}