反射
在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
每种语言的反射模型都不同,并且有些语言根本不支持反射。Golang语言实现了反射,反射机制就是在运行时动态的调用对象的方法和属性,官方自带的reflect包就是反射相关的,只要包含这个包就可以使用。
TypeOf和ValueOf
在Go的反射定义中,任何接口都会由两部分组成的,一个是接口的具体类型,一个是具体类型对应的值。比如var i int = 3 ,因为interface{}可以表示任何类型,所以变量i可以转为interface{},所以可以把变量i当成一个接口,那么这个变量在Go反射中的表示就是<Value,Type>,其中Value为变量的值3,Type变量的为类型int。
在Go反射中,标准库为我们提供两种类型来分别表示他们reflect.Value和reflect.Type,并且提供了两个函数来获取任意对象的Value和Type。
package main
import (
"fmt"
"reflect"
)
type User struct {
Name string
Age int
}
func main() {
u := User{"张三", 20}
t := reflect.TypeOf(u)
fmt.Println(t)
}
输出结果为:
main.User
package main
import (
"fmt"
"reflect"
)
type User struct {
Name string
Age int
}
func main() {
u := User{"张三", 20}
t := reflect.ValueOf(u)
fmt.Println(t)
}
输出结果为:
{张三 20}
reflect.Value转原始类型
上面的例子我们可以通过reflect.ValueOf函数把任意类型的对象转为一个reflect.Value,那我们如果我们想逆向转过回来呢,其实也是可以的,reflect.Value为我们提供了Inteface方法来帮我们做这个事情。继续接上面的例子:
package main
import (
"fmt"
"reflect"
)
type User struct {
Name string
Age int
}
func main() {
u := User{"张三", 20}
t := reflect.ValueOf(u)
u1 := t.Interface().(User)
fmt.Println(u1)
fmt.Println(reflect.TypeOf(t))
fmt.Println(reflect.TypeOf(u1))
}
输出结果为:
{张三 20}
reflect.Value
main.User
获取类型底层类型
底层的类型是什么意思呢?其实对应的主要是基础类型,接口、结构体、指针这些,因为我们可以通过type关键字声明很多新的类型,比如上面的例子,对象u的实际类型是User,但是对应的底层类型是struct这个结构体类型,我们来验证下。
package main
import (
"fmt"
"reflect"
)
type User struct {
Name string
Age int
}
func main() {
u := User{"张三", 20}
t := reflect.ValueOf(u)
u1 := t.Interface().(User)
fmt.Println(u1)
fmt.Println(t.Kind())
}
输出结果为:
{张三 20}
struct
Go语言提供了以下这些最底层的类型,可以看到,都是最基本的。
const (
Invalid Kind = iota
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Ptr
Slice
String
Struct
UnsafePointer
)
遍历字段和方法
for i:=0;i<t.NumField();i++ {
fmt.Println(t.Field(i).Name)
}
for i:=0;i<t.NumMethod() ;i++ {
fmt.Println(t.Method(i).Name)
}
修改字段的值
func main() {
x:=2
v:=reflect.ValueOf(&x)
v.Elem().SetInt(100)
fmt.Println(x)
}
动态调用方法
func main() {
u:=User{"张三",20}
v:=reflect.ValueOf(u)
mPrint:=v.MethodByName("Print")
args:=[]reflect.Value{reflect.ValueOf("前缀")}
fmt.Println(mPrint.Call(args))
}
type User struct{
Name string
Age int
}
func (u User) Print(prfix string){
fmt.Printf("%s:Name is %s,Age is %d",prfix,u.Name,u.Age)
}