反射的结构体
//reflect/type.go
type Type interface {
// 该类型内存分配大小(内存对齐单位子节)
Align() int
// 该类型作为结构体字段时内存分配大小(内存对齐单位子节)
FieldAlign() int
// 根据index in [0, NumMethod())获取方法 按lexicographic排序
Method(int) Method
// 根据方法名获取方法
MethodByName(string) (Method, bool)
// 获取所有可用方法数量
// 接口类型 获取包含未导出方法
NumMethod() int
// 返回类型名,未定义则为空
Name() string
// 返回类型所在包名,未定义则为空
PkgPath() string
// 错误类型所需子节数 unsafe.Sizeof.
Size() uintptr
// 返回类型名称字符串
String() string
// 返回此类型的kind类型
Kind() Kind
// 返回是否实现了u接口
Implements(u Type) bool
// 返回类型的值是否可分配给类型u
AssignableTo(u Type) bool
// 返回类型的值是否可以转换为u类型
ConvertibleTo(u Type) bool
// 返回类型的值是否可对比
Comparable() bool
// Methods applicable only to some types, depending on Kind.
// The methods allowed for each kind are:
//
// Int*, Uint*, Float*, Complex*: Bits
// Array: Elem, Len
// Chan: ChanDir, Elem
// Func: In, NumIn, Out, NumOut, IsVariadic.
// Map: Key, Elem
// Ptr: Elem
// Slice: Elem
// Struct: Field, FieldByIndex, FieldByName, FieldByNameFunc, NumField
// Bits returns the size of the type in bits.
// It panics if the type's Kind is not one of the
// sized or unsized Int, Uint, Float, or Complex kinds.
Bits() int
// Elem返回类型的元素类型
// 不是 Array, Chan, Map, Ptr, or Slice. panic
Elem() Type
// --------------- struct ------------------------
// 字段返回结构类型的第i个字段。
// 不是struct 或者下表越界 painc
Field(i int) StructField
// 字段返回嵌套结构类型的第i个字段。
// 不是struct 或者下表越界 painc
FieldByIndex(index []int) StructField
// 按名称返回字段
FieldByName(name string) (StructField, bool)
// 按过滤方法返回匹配字段
FieldByNameFunc(match func(string) bool) (StructField, bool)
// 返回结构体字段总数
// 不是 Struct panic.
NumField() int
// --------------- struct ------------------------
// --------------- func --------------------
//返回函数类型第i的输入参数
// 不是Func painc
In(i int) Type
// 返回方法输入参数总数
// 不是Func painc
NumIn() int
// 返回函数输出参数总数
// 不是Func painc
NumOut() int
// 返回函数类型第i的输出参数
// 不是Func painc
Out(i int) Type
// 返回函数是否包含可变参数
// 不是Func painc
IsVariadic() bool
// --------------- func --------------------
// --------------- Map --------------------
// 返回map的key类型
// 不是Map panic
Key() Type
// --------------- Map --------------------
// --------------- Array --------------------
// 返回数组类型的长度
// 不是Array panic
Len() int
// --------------- Array --------------------
// --------------- chan --------------------
// 返回chan类型的方向,不是chan会panic
ChanDir() ChanDir
// --------------- chan --------------------
common() *rtype
uncommon() *uncommonType
}
反射三定律
反射包里有两个接口类型要先了解一下.
reflect.Type 提供一组接口处理interface的类型,即(value, type)中的type
reflect.Value提供一组接口处理interface的值,即(value, type)中的value
下面会提到反射对象,所谓反射对象即反射包里提供的两种类型的对象。
reflect.Type 类型对象
reflect.Value类型对象
反射第一定律:反射可以将interface类型变量转换成反射对象
package main
import (
"fmt"
"reflect"
)
func main() {
var x float64 = 3.4
t := reflect.TypeOf(x) //t is reflect.Type
fmt.Println("type:", t)
v := reflect.ValueOf(x) //v is reflect.Value
fmt.Println("value:", v)
}
程序输出如下:
type: float64
value: 3.4
注意:反射是针对interface类型变量的,其中TypeOf()和ValueOf()接受的参数都是interface{}类型的,也即x值是被转成了interface传入的。
除了reflect.TypeOf()和reflect.ValueOf(),还有其他很多方法可以操作,本文先不过多介绍,否则一不小心会会引起困惑。
反射第二定律:反射可以将反射对象还原成interface对象
package main
import (
"fmt"
"reflect"
)
func main() {
var x float64 = 3.4
v := reflect.ValueOf(x) //v is reflect.Value
var y float64 = v.Interface().(float64)
fmt.Println("value:", y)
}
对象x转换成反射对象v,v又通过Interface()接口转换成interface对象,interface对象通过.(float64)类型断言获取float64类型的值。
反射第三定律:反射对象可修改,value值必须是可设置的
通过反射可以将interface类型变量转换成反射对象,可以使用该反射对象设置其持有的值。在介绍何谓反射对象可修改前,先看一下失败的例子:
package main
import (
"reflect"
)
func main() {
var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1) // Error: will panic.
}
如下代码,通过反射对象v设置新值,会出现panic。报错如下:
panic: reflect: reflect.Value.SetFloat using unaddressable value
错误原因即是v是不可修改的。
反射对象是否可修改取决于其所存储的值,回想一下函数传参时是传值还是传址就不难理解上例中为何失败了。
上例中,传入reflect.ValueOf()函数的其实是x的值,而非x本身。即通过v修改其值是无法影响x的,也即是无效的修改,所以golang会报错。
想到此处,即可明白,如果构建v时使用x的地址就可实现修改了,但此时v代表的是指针地址,我们要设置的是指针所指向的内容,也即我们想要修改的是*v。 那怎么通过v修改x的值呢?
reflect.Value提供了Elem()方法,可以获得指针向指向的value。看如下代码:
package main
import (
"reflect"
"fmt"
)
func main() {
var x float64 = 3.4
v := reflect.ValueOf(&x)
v.Elem().SetFloat(7.1)
fmt.Println("x :", v.Elem().Interface())
}
输出为:
x : 7.1
如何通过反射来进行结构体方法的调用?
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int
Sex string
}
func (p Person)Say(msg string) {
fmt.Println("hello,",msg)
}
func (p Person)PrintInfo() {
fmt.Printf("姓名:%s,年龄:%d,性别:%s\n",p.Name,p.Age,p.Sex)
}
func (p Person) Test(i,j int,s string){
fmt.Println(i,j,s)
}
// 如何通过反射来进行方法的调用?
// 本来可以用结构体对象.方法名称()直接调用的,
// 但是如果要通过反射,
// 那么首先要将方法注册,也就是MethodByName,然后通过反射调动mv.Call
func main() {
p2 := Person{"张三",20,"男"}
// 1. 要通过反射来调用起对应的方法,必须要先通过reflect.ValueOf(interface)来获取到reflect.Value,
// 得到“反射类型对象”后才能做下一步处理
getValue := reflect.ValueOf(p2)
// 2.一定要指定参数为正确的方法名
// 先看看没有参数的调用方法
methodValue1 := getValue.MethodByName("PrintInfo")
fmt.Printf("Kind : %s, Type : %s\n",methodValue1.Kind(),methodValue1.Type())
methodValue1.Call(nil) //没有参数,直接写nil
args1 := make([]reflect.Value, 0) //或者创建一个空的切片也可以
methodValue1.Call(args1)
// 有参数的方法调用
methodValue2 := getValue.MethodByName("Say")
fmt.Printf("Kind : %s, Type : %s\n",methodValue2.Kind(),methodValue2.Type())
args2 := []reflect.Value{reflect.ValueOf("反射机制")}
methodValue2.Call(args2)
methodValue3 := getValue.MethodByName("Test")
fmt.Printf("Kind : %s, Type : %s\n",methodValue3.Kind(),methodValue3.Type())
args3 := []reflect.Value{reflect.ValueOf(5), reflect.ValueOf(2),reflect.ValueOf("you")}
methodValue3.Call(args3)
}
Kind : func, Type : func()
姓名:张三,年龄:20,性别:男
姓名:张三,年龄:20,性别:男
Kind : func, Type : func(string)
hello, 反射机制
Kind : func, Type : func(int, int, string)
5 2 you
如何通过反射来进行方法的调用?
package main
import (
"fmt"
"reflect"
)
func main() {
//函数的反射
f1 := fun1
value := reflect.ValueOf(f1)
fmt.Printf("Kind : %s , Type : %s\n",value.Kind(),value.Type()) //Kind : func , Type : func()
value2 := reflect.ValueOf(fun2)
fmt.Printf("Kind : %s , Type : %s\n",value2.Kind(),value2.Type()) //Kind : func , Type : func(int, string)
//通过反射调用函数
value.Call(nil)
value2.Call([]reflect.Value{reflect.ValueOf("hello"),reflect.ValueOf(61)})
}
func fun1(){
fmt.Println("我是函数fun1(),无参的。")
}
func fun2(s string, i int){
fmt.Println("我是函数fun2(),有参数:",s,i)
}
Kind : func , Type : func()
Kind : func , Type : func(string, int)
我是函数fun1(),无参的。
我是函数fun2(),有参数: hello 61
反射未导出的字段
package main
import (
"fmt"
"reflect"
)
type Student struct {
name string
Age int
}
func main() {
var TestStudent = Student{name: "jack",Age: 12,}
fmt.Printf("testStudent.name: %v\n", getUnExportedField(&TestStudent, "name"))
}
func getUnExportedField(ptr interface{}, fieldName string) reflect.Value {
v := reflect.ValueOf(ptr).Elem().FieldByName(fieldName)
return v
}
//输出 testStudent.name: jack
总结--综合
package main
import (
"fmt"
"reflect"
)
type People struct {
Age int
Name string
}
type TestInterface interface {
GetName() string
}
func (p *People) UpdateName(newName string) {
p.Name = newName
}
func (p *People) GetName() string {
return p.Name
}
func main() {
u := People{18, "kuteng"}
//返回指定对象的Kind类型
fmt.Println(reflect.TypeOf(32).Kind())
fmt.Println(reflect.ValueOf(32).Kind())
//根据方法名找方法
fmt.Println(reflect.TypeOf(&u).MethodByName("UpdateName"))
fmt.Println(reflect.ValueOf(&u).MethodByName("UpdateName"))
//返回第i个方法
fmt.Println(reflect.TypeOf(&u).Method(0))
fmt.Println(reflect.ValueOf(&u).Method(0))
//返回拥有的方法总数,包括unexported方法
fmt.Println(reflect.TypeOf(&u).NumMethod())
fmt.Println(reflect.ValueOf(&u).NumMethod())
//取struct结构的第n个field
fmt.Println(reflect.TypeOf(u).Field(0))
fmt.Println(reflect.ValueOf(u).Field(1))
//嵌套的方式取struct的field,比如v.FieldByIndex(1,2,3)等价于 v.field(1).field(2).field(3)
fmt.Println(reflect.TypeOf(u).FieldByIndex([]int{0}))
fmt.Println(reflect.ValueOf(u).FieldByIndex([]int{0}))
//返回名称匹配match函数的field
fmt.Println(reflect.TypeOf(u).FieldByName("ID"))
fmt.Println(reflect.ValueOf(u).FieldByName("Name"))
//返回struct所包含的field数量
fmt.Println(reflect.TypeOf(u).NumField())
fmt.Println(reflect.ValueOf(u).NumField())
//分配内存时的内存对齐字节数
fmt.Println(reflect.TypeOf(u).Align())
//作为struct的field时内存对齐字节数
fmt.Println(reflect.TypeOf(u).FieldAlign())
//type名 string类型
fmt.Println(reflect.TypeOf(u).Name())
//包路径, "encoding/base64", 内置类型返回empty string
fmt.Println(reflect.TypeOf(u).PkgPath())
//该类型变量占用字节数
fmt.Println(reflect.TypeOf(u).Size())
//type的string表示方式
fmt.Println(reflect.TypeOf(u).String())
//判断该类型是否实现了某个接口
fmt.Println(reflect.TypeOf(u).Implements(reflect.TypeOf((*TestInterface)(nil)).Elem()))
//判断该类型能否赋值给某个类型
fmt.Println(reflect.TypeOf(u).AssignableTo(reflect.TypeOf(People{})))
//判断该类型能否转换为另外一种类型
fmt.Println(reflect.TypeOf(u).ConvertibleTo(reflect.TypeOf(1)))
//判断该类型变量是否可以比较
fmt.Println(reflect.TypeOf(u).Comparable())
//取该类型的元素,指针指向的结构
fmt.Println(reflect.TypeOf(&u).Elem())
//调用函数
fmt.Println(reflect.ValueOf(&u).MethodByName("GetName").Call([]reflect.Value{}))
//判断能否取地址
fmt.Println(reflect.ValueOf(&u).CanAddr())
//判断Interface方法能否使用
fmt.Println(reflect.ValueOf(&u).CanInterface())
//判断值能否改变
fmt.Println(reflect.ValueOf(&u).CanSet())
a := []int{0, 1}
//获取容量 Array/Chan/Slice
fmt.Println(reflect.ValueOf(a).Cap())
c := make(chan int)
//关闭channel
reflect.ValueOf(c).Close()
//返回指针实际的值
fmt.Println(reflect.ValueOf(&u).Elem())
//索引操作 Array/Slice/String
fmt.Println(reflect.ValueOf(a).Index(0))
//修改数组第一个索引的值
reflect.ValueOf(a).Index(0).Set(reflect.ValueOf(1))
fmt.Println(a[0])
//将当前value以interface形式返回
fmt.Println(reflect.ValueOf(&u).Interface())
//判断是否为nil,chan, func, interface, map, pointer, or slice valu
fmt.Println(reflect.ValueOf(&u).IsNil())
//是否是可操作的Value,返回false表示为zero Value
fmt.Println(reflect.ValueOf(&u).IsValid())
//获取长度,适用于Array, Chan, Map, Slice, or String
fmt.Println(reflect.ValueOf(a).Len())
m := map[int]string{1: "topgoer.com", 2: "topgoer.cn"}
//对map类型按key取值
fmt.Println(reflect.ValueOf(m).MapIndex(reflect.ValueOf(1)))
//map类型的所有key的列表
for index, key := range reflect.ValueOf(m).MapKeys() {
fmt.Println("key=", key)
fmt.Println("idnex=", index)
}
//返回value的Type
fmt.Println(reflect.ValueOf(1).Type())
}