一、反射的基础
1.什么是反射
- Go语言中,反射的机制就是在运行的时候,可以获取到其变量的类型和值,且可以对其类型和值进行检查,对其值进行修改。
- 即在不知道具体的类型的情况下,可以用反射机制来查看变量类型、更新变量的值。
- Go中反射主要涉及到两个概念:Type和Value。对所有的接口进行反射时,都可以得到一个包含Type和Value的信息结构,Type是反射的这个变量本身的类型信息,Value是反射的这个变量本身的值信息。
2.反射的使用
(1) 获取到变量类型
package main
import (
"fmt"
"reflect"
)
func main(){
x := 3.1415
y := 3
z := "sheena"
u := true
fmt.Println("x的type为:", reflect.TypeOf(x))
fmt.Println("y的type为:", reflect.TypeOf(y))
fmt.Println("z的type为:", reflect.TypeOf(z))
fmt.Println("u的type为:", reflect.TypeOf(u))
}
(2) 进行变量类型判断
package main
import (
"fmt"
"reflect"
)
func main(){
x := 3.1415
y := 3
z := "sheena"
u := true
//获取变量的类型
xtype := reflect.TypeOf(x)
ytype := reflect.TypeOf(y)
ztype := reflect.TypeOf(z)
utype := reflect.TypeOf(u)
//Kind()方法的返回结果主要是用来进行类型判断的
xkind := xtype.Kind()
ykind := ytype.Kind()
zkind := ztype.Kind()
ukind := utype.Kind()
//对x进行类型判断
if xkind == reflect.String{
fmt.Println("x的type是string")
}else if xkind == reflect.Float64{
fmt.Println("x的type是float64")
}
//对y进行类型判断
if ykind == reflect.Float64{
fmt.Println("y的type是Float64")
}else if ykind == reflect.Int{
fmt.Println("y的type是int")
}
//对z进行类型判断
if zkind == reflect.Float64{
fmt.Println("z的type是Float64")
}else if zkind == reflect.String{
fmt.Println("z的type是string")
}
//对u进行类型判断
if ukind == reflect.Bool{
fmt.Println("u的type是bool")
}else if ukind == reflect.String{
fmt.Println("u的type是string")
}
}
(3) 获取到变量值
package main
import (
"fmt"
"reflect"
)
func main(){
x := 3.1415
y := 3
z := "sheena"
u := true
fmt.Println("x的value为:", reflect.ValueOf(x))
fmt.Println("y的value为:", reflect.ValueOf(y))
fmt.Println("z的value为:", reflect.ValueOf(z))
fmt.Println("u的value为:", reflect.ValueOf(u))
}
(4) 修改变量值
package main
import (
"fmt"
"reflect"
)
func main(){
x := 3.1415
y := 3
z := "sheena"
u := true
fmt.Println("x修改前的value为:", reflect.ValueOf(x))
fmt.Println("y修改前的value为:", reflect.ValueOf(y))
fmt.Println("z修改前的value为:", reflect.ValueOf(z))
fmt.Println("u修改前的value为:", reflect.ValueOf(u))
//通过反射传入变量x的地址,并且通过Ele
rex := reflect.ValueOf(&x).Elem()
rey := reflect.ValueOf(&y).Elem()
rez := reflect.ValueOf(&z).Elem()
reu := reflect.ValueOf(&u).Elem()
//判断是否可以修改变量x的值,若可以,则用SetFLoat64()方法进行修改
if rex.CanSet(){
rex.SetFloat(61.23466)
fmt.Println("x修改后的value为:", reflect.ValueOf(x))
}else {
fmt.Println("该变量不能修改")
}
if rey.CanSet(){
rey.SetInt(10000)
fmt.Println("y修改后的value为:", reflect.ValueOf(y))
}else {
fmt.Println("该变量不能修改")
}
if rez.CanSet(){
rez.SetString("hello world")
fmt.Println("z修改后的value为:", reflect.ValueOf(z))
}else{
fmt.Println("该变量不能修改")
}
if reu.CanSet(){
reu.SetBool(false)
fmt.Println("u修改后的value为:", reflect.ValueOf(u))
}else {
fmt.Println("该变量不能修改")
}
}
package main
import (
"fmt"
"reflect"
)
func main(){
x := 3.1415
y := 3
z := "sheena"
u := true
fmt.Println("x修改前的value为:", reflect.ValueOf(x))
fmt.Println("y修改前的value为:", reflect.ValueOf(y))
fmt.Println("z修改前的value为:", reflect.ValueOf(z))
fmt.Println("u修改前的value为:", reflect.ValueOf(u))
//通过反射传入变量x的地址,并且通过Ele
rex := reflect.ValueOf(&x).Elem()
rey := reflect.ValueOf(&y).Elem()
rez := reflect.ValueOf(&z).Elem()
reu := reflect.ValueOf(&u).Elem()
//判断是否可以修改变量x的值,若可以,则用Set()方法进行修改
if rex.CanSet(){
ax := reflect.ValueOf(61.23466) // 使用Set方法修改值,Set方法接收的是ValueOf的返回值
rex.Set(ax)
fmt.Println("x修改后的value为:", reflect.ValueOf(x))
}else {
fmt.Println("该变量不能修改")
}
if rey.CanSet(){
ay := reflect.ValueOf(10000)// 使用Set方法修改值,Set方法接收的是ValueOf的返回值
rey.Set(ay)
fmt.Println("y修改后的value为:", reflect.ValueOf(y))
}else {
fmt.Println("该变量不能修改")
}
if rez.CanSet(){
az := reflect.ValueOf("hello world")// 使用Set方法修改值,Set方法接收的是ValueOf的返回值
rez.Set(az)
fmt.Println("z修改后的value为:", reflect.ValueOf(z))
}else{
fmt.Println("该变量不能修改")
}
if reu.CanSet(){
au := reflect.ValueOf(false)// 使用Set方法修改值,Set方法接收的是ValueOf的返回值
reu.Set(au)
fmt.Println("u修改后的value为:", reflect.ValueOf(u))
}else {
fmt.Println("该变量不能修改")
}
}
(5) 获取变量的指针所指向的对象
package main
import (
"fmt"
"reflect"
)
func main(){
x := 3.1415
y := 3
z := "sheena"
u := true
//传入变量地址
px := reflect.ValueOf(&x)
py := reflect.ValueOf(&y)
pz := reflect.ValueOf(&z)
pu := reflect.ValueOf(&u)
fmt.Println("x的地址是", px)
fmt.Println("y的地址是", py)
fmt.Println("z的地址是", pz)
fmt.Println("u的地址是", pu)
//通过变量地址获取到变量的值
xe := px.Elem()
ye := py.Elem()
ze := pz.Elem()
ue := pu.Elem()
fmt.Println("x的值是", xe)
fmt.Println("y的值是", ye)
fmt.Println("z的值是", ze)
fmt.Println("u的值是", ue)
}
(6) 获取结构体变量的类型和值
package main
import (
"fmt"
"reflect"
)
type Stu struct{
Name string
Age int
Sex string
IsCan bool
}
func main(){
s1 := Stu{Name: "王一", Age: 18, Sex: "男", IsCan: false}
s2 := Stu{Name: "王二", Age: 19, Sex: "女", IsCan: true}
s3 := Stu{Name: "张三", Age: 20, Sex: "男", IsCan: false}
//反射获取结构体的类型和值
fmt.Println("s1的类型", reflect.TypeOf(s1))
fmt.Println("s1的值", reflect.ValueOf(s1))
fmt.Println("s2的类型", reflect.TypeOf(s2))
fmt.Println("s2的值", reflect.ValueOf(s2))
fmt.Println("s3的类型", reflect.TypeOf(s3))
fmt.Println("s3的值", reflect.ValueOf(s3))
fmt.Println("TypeOf()和Kind()方法输出的区别")
fmt.Println("TypeOf(s1):", reflect.TypeOf(s1))
s1tp := reflect.TypeOf(s1)
fmt.Println("Kind(s1):", s1tp.Kind())
}
结果:
二、反射的原理
1.反射如何获取类型信息
func TypeOf(i interface{}) Type{
eface := *(*emptyInterface)(unsafe.Pointer(&i))
return toType(eface.type)
}
//Type接口提供了一系列方法
type Type interface{
Align() int //对齐边界
FieldAlign() int
Method(int) Method
MethodByName(string) (Method, bool) //方法
NumMethod() int //类型名称
Name() string
PkgPath() string //包路径
Slize() uintptr
String() string
Kind() Kind
Implements(u Type) bool //是否实现指定接口
AssginableTo(u Type) bool
ConvertibleTo(u Type) bool
Comparable() bool //是否可比较
}
2.反射如何修改变量值
type Value struct {
type *rtype
ptr unsafe.Pointer
flag
}
func ValueOf(i interface{}) Value{
if i == nill{
return Value()
}
escapes(i)
return unpackEface(i)
}