Go 的反射reflection
1.反射可以大大提升程序的灵活性,使得interface{}有更大的发挥余地
2.反射使用TypeOf和ValueOf函数从接口中获得目标对象的信息
3.反射会将匿名字段作为独立的字段
4.想要利用反射修改对象的状态,前提是interface.data是settable,即pointer-interface
5.通过反射可以动态的调用方法
以下举个例子
package main
import (
"fmt"
"reflect"
)
type User struct {
Id int
Name string
Age int
}
func (u User) Hello() {
fmt.Println("Hello,",u.Name)
}
func main() {
u := User{1, "Jack", 14}
Info(u)
}
func Info(o interface{}){
t := reflect.TypeOf(o)
fmt.Println("Type:",t.Name())
v := reflect.ValueOf(o)
fmt.Println("Fields:",v)
//取得字段信息
for i :=0;i<t.NumField();i++{
f :=t.Field(i)
val := v.Field(i).Interface()
fmt.Printf("%6s: %v = %v \n",f.Name,f.Type,val)
}
//取得方法信息
for i :=0;i <t.NumMethod();i++{
m :=t.Method(i)
fmt.Printf("%6s: %v\n",m.Name,m.Type)
}
}
输出的结果是
Type: User Fields: {1 Jack 14} Id: int = 1 Name: string = Jack Age: int = 14 Hello: func(main.User)
通过反射修改目标对象
package main
import (
"fmt"
"reflect"
)
func main() {
x := 123
v := reflect.ValueOf(&x)
v.Elem().SetInt(999)
fmt.Println(x)
}
结果是 999
通过反射修改目标结构体内容
package main
import (
"fmt"
"reflect"
)
type User struct {
Id int
Name string
Age int
}
func main() {
u := User{1,"Jack",12}
Set(&u)
fmt.Println("Name:",u.Name)
}
func Set(o interface{}) {
v := reflect.ValueOf(o)
if v.Kind() == reflect.Ptr && !v.Elem().CanSet(){
fmt.Println("XXX")
return
}else{
v = v.Elem()
}
f:=v.FieldByName("Name")
if !f.IsValid(){
fmt.Println("Bad")
return
}
if f.Kind()==reflect.String{
f.SetString("Tom")
}
}
修改之后Name从Jack改成了Tom
通过反射来调用方法
package main
import (
"fmt"
"reflect"
)
type User struct {
Id int
Name string
Age int
}
func (u User) Hello(name string){
fmt.Println("Hello,",name,".my name is ",u.Name)
}
func main() {
u := User{1,"Jack",12}
v := reflect.ValueOf(u)
mv := v.MethodByName("Hello")
args := []reflect.Value{reflect.ValueOf("Tom")}
mv.Call(args)
}
执行结果:
Hello, Tom .my name is Jack