【Golang】反射机制

反射

在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(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)
}
参考

https://blog.golang.org/laws-of-reflection

上一篇:Go 之反射


下一篇:golang 之反射