Name and Kind

可调用函数和含义,以及结果一览

1
2
3
4
5
6
7
8
9
10
11
12
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

1
2
3
valueOfA := reflect.ValueOf(a)
var getA int = valueOfA.Interface().(int)
var getA2 int = int(valueOfA.Int())

通过反射获取值信息

使用反射值对象包装任意值

Go语言中,使用 reflect.ValueOf() 函数获得值的反射值对象(reflect.Value)。书写格式如下:

1
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() 方法获得整型值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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()

结构体成员中,如果字段没有被导出,即便不使用反射也可以被访问,但不能通过反射修改

  1. 指针指向的具体元素

    1
    2
    3
    x := 1
    v := reflect.ValueOf(&x)
    v = v.Elem()
  2. slice的元素

    1
    2
    3
    s := []int{1,1}
    v := reflect.ValueOf(s)
    e := v.Index(0)
  3. 可寻址的结构体的字段(指向结构体的指针)

    1
    2
    3
    4
    5
    6
    7
    type Orange struct{
    Size int
    }
    a := Orange{99}
    v := reflect.ValueOf(&a)
    v = v.Elem()
    field = v.FieldByName("field")
  4. 可寻址的数组的元素(指向数组的指针)

    1
    2
    3
    4
    5
    6
    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 时会发生宕机

通过类型信息创建实例

1
2
3
4
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"

注意:

  1. key:“value” 冒号后没有空格
  2. 两个key之间,一个空格,多一个都不行
1
2
3
4
type cat struct{
Name string
Type int `json:"type" id:"100"`
}

从结构体标签中获取值

1
2
3
typeOfCat := reflect.TypeOf(cat{})
catType = typeOfCat.FieldByName("Type")
catType.Tag.Get("json")

常见用法

动态调用函数(无参数)

  1. 直接reflect.Valueof
  2. MethodByName
  3. 调用Call方法
1
2
3
4
5
6
7
8
9
10
11
type T struct {}

func main() {
name := "Do"
t := &T{}
reflect.ValueOf(t).MethodByName(name).Call(nil)
}

func (t *T) Do() {
fmt.Println("hello")
}

动态调用函数(有参数)

  1. 创建reflect.Value切片
  2. reflect.Valueof(t).MethodByName(string) 调用Call方法传入参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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)
}

接收返回值

  1. 返回[]reflect.Value
  2. 调用Interface()方法,转为interface{}类型
  3. 断言类型
1
2
3
4
5
6
7
8
9
10
11
12
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解析

  1. reflect.TypeofNumField,Field根据序号索取,取其中的tag
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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()处理不同分支

  1. reflect.Typeof().Kind()
1
2
3
4
5
6
7
8
9
10
11
12
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")
}
}

判断结构体是否实现接口

  1. nil强转为接口指针类型,通过reflect.Typeof().Elem获取其接口类型
  2. reflect.Typeof调用方法Implements来判断
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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")
}
}

直接通过接口强转判断

  1. 将类型转换为 reflect.Value
  2. reflect.Value调用Interface()方法转为接口类型
  3. 类型断言
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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)
}
}