目录
概念:运行时动态的获取变量的相关信息。
反射:对一些对象进行序列化处理
Import ("reflect)
1,reflect
-
reflect. TypeOf,获取变量的类型,返回reflect Type类型
-
reflect ValueOf,获取变量的值,返回reflect .Value类型
-
reflect.Value Kind, 获取变量的类别,返回一个常量
-
reflect Value .Interface(),转换成interface{}类型
示例:获取变量类型
package main
import (
"fmt"
"reflect"
)
//定义一个函数
func Test(i interface{}) {
//反射数据类型
t := reflect.TypeOf(i)
fmt.Println("类型是:", t)
//反射数据值
y := reflect.ValueOf(i)
fmt.Println("类型是:", y)
}
func main() {
a := "hello"
Test(a)
}
[Running] go run "f:\goProject\src\dev_code\day23\example1\main.go"
类型是: string
类型是: hello
[Done] exited with code=0 in 0.73 seconds
示例:类型和类别
package main
import (
"fmt"
"reflect"
)
//类型和类别
//定义结构体
type student struct {
name string
age int
score float32
}
//函数传入
func Test(i interface{}) {
//反射数据类型
t := reflect.TypeOf(i)
fmt.Println("类型是:", t)
//类别
y := reflect.ValueOf(i) //或者u:=reflect.ValueOf(i).Kind()
u := y.Kind()
fmt.Println("值是:", y)
fmt.Println("类别是:", u) //类别是一个常量
}
func main() {
var stu student
stu.name = "zhangsan"
stu.age = 20
stu.score = 50
Test(stu)
fmt.Println("<<<--------我是华丽的分割线--------->>>")
var num int = 10
Test(num)
}
[Running] go run "f:\goProject\src\dev_code\day23\example2\main\main.go"
类型是: main.student
值是: {zhangsan 20 50}
类别是: struct
<<<--------我是华丽的分割线--------->>>
类型是: int
值是: 10
类别是: int
[Done] exited with code=0 in 0.6 seconds
示例:断言处理类型转换
package main
import (
"fmt"
"reflect"
)
//类型和类别
//定义结构体
type student struct {
name string
age int
score float32
}
//函数传入
func Test(i interface{}) {
//反射数据类型
t := reflect.TypeOf(i)
fmt.Println("类型是:", t)
//类别
y := reflect.ValueOf(i) //或者u:=reflect.ValueOf(i).Kind()
u := y.Kind()
fmt.Println("类别是:", u) //类别是一个常量
fmt.Printf("y的类型是%T\n", y)
fmt.Printf("u的类型是%T\n", u)
//转化成接口
iy := y.Interface()
fmt.Printf("iy的类型是%T\n", iy)
//断言处理iy是student类型是true就赋值给stu_iy
stu_iy, ok := iy.(student)
if ok {
fmt.Printf("stu_iy的类型是%T\n", stu_iy)
}
}
func main() {
var stu student
stu.name = "zhangsan"
stu.age = 20
stu.score = 50
Test(stu)
}
[Running] go run "f:\goProject\src\dev_code\day23\example2\main\main.go"
类型是: main.student
类别是: struct
y的类型是reflect.Value
u的类型是reflect.Kind
iy的类型是main.student
stu_iy的类型是main.student
[Done] exited with code=0 in 0.474 seconds
2,valueOf
获取变量值
reflect. Value0f(x)- Float()
reflect. Value0f(x).Int( )
reflect . ValueOf(x) . String( )
reflect . ValueOf(x). Bool()
示例:类型转换
package main
import (
"fmt"
"reflect"
)
//定义函数传入
func Test(i interface{}) {
fmt.Printf("i的类型:%T\n", i)
v := reflect.ValueOf(i)
fmt.Printf("v的类型:%T\n", v)
//转换指定类型
t := v.Int()
fmt.Printf("t的类型:%T\n", t)
}
func main() {
var num int = 10
Test(num)
}
[Running] go run "f:\goProject\src\dev_code\day23\example3\main\main.go"
i的类型:int
v的类型:reflect.Value
t的类型:int64
[Done] exited with code=0 in 0.616 seconds
不同类型会出错
package main
import (
"fmt"
"reflect"
)
//定义函数传入
func Test(i interface{}) {
fmt.Printf("i的类型:%T\n", i)
v := reflect.ValueOf(i)
fmt.Printf("v的类型:%T\n", v)
//转换指定类型
t := v.Int()
fmt.Printf("t的类型:%T\n", t)
}
func main() {
var num string = "10"
Test(num)
}
[Running] go run "f:\goProject\src\dev_code\day23\example3\main\main.go"
i的类型:string
v的类型:reflect.Value
panic: reflect: call of reflect.Value.Int on string Value
goroutine 1 [running]:
reflect.Value.Int(...)
C:/Program Files/Go/src/reflect/value.go:1347
main.Test({0x8b5b20, 0xc00005a230})
f:/goProject/src/dev_code/day23/example3/main/main.go:14 +0x297
main.main()
f:/goProject/src/dev_code/day23/example3/main/main.go:19 +0x34
exit status 2
[Done] exited with code=1 in 0.589 seconds
3,value.set
设置变量值
reflect. value . SetFloat(),设置浮点数
reflect. value . SetInt(),设置整数
reflect value . SetString(),设置字符串
示例:报错
package main
import (
"fmt"
"reflect"
)
//定义函数传入
func Test(i interface{}) {
v := reflect.ValueOf(i)
//更新值
v.SetInt(100)
result := v.Int()
fmt.Printf("更改后的类型是:%T,值是:%d\n", result, result)
}
func main() {
var num int = 10
Test(num)
}
[Running] go run "f:\goProject\src\dev_code\day23\example4\main\main.go"
panic: reflect: reflect.Value.SetInt using unaddressable value
goroutine 1 [running]:
reflect.flag.mustBeAssignableSlow(0xc000028000)
C:/Program Files/Go/src/reflect/value.go:262 +0x85
reflect.flag.mustBeAssignable(...)
C:/Program Files/Go/src/reflect/value.go:249
reflect.Value.SetInt({0x795460, 0x837870, 0x100000000000000}, 0x64)
C:/Program Files/Go/src/reflect/value.go:1991 +0x48
main.Test({0x795460, 0x837870})
f:/goProject/src/dev_code/day23/example4/main/main.go:12 +0xc5
main.main()
f:/goProject/src/dev_code/day23/example4/main/main.go:19 +0x2d
exit status
[Done] exited with code=1 in 0.563 seconds
传入更改需要传指针,示例:
package main
import (
"fmt"
"reflect"
)
//定义函数传入
func Test(i interface{}) {
v := reflect.ValueOf(i)
//更新值需要value的地址,否则会崩溃Elem()表示* 传入指针
v.Elem().SetInt(100)
result := v.Elem().Int()
fmt.Printf("更改后的类型是:%T,值是:%d\n", result, result)
}
func main() {
var num int = 10
Test(&num)//传入地址
}
[Running] go run "f:\goProject\src\dev_code\day23\example4\main\main.go"
更改后的类型是:int64,值是:100
[Done] exited with code=0 in 0.588 seconds
4,结构体的反射
示例:反射出结构体属性和方法数量。注意:方法名需要大写,相当于跨包调用
package main
import (
"fmt"
"reflect"
)
//结构体反射
type student struct {
name string
age int
score float32
}
//结构体方法
func (s student) Run() { //方法名需要大写,反射相当于跨包调用
fmt.Println("正在跑步")
}
func (s student) Sleep() {
fmt.Println("正在睡觉")
}
//定义函数使用反射查看结构体字段数量和方法数量
func Test(i interface{}) {
v := reflect.ValueOf(i)
//类别判断
if v.Kind() != reflect.Struct {
fmt.Println("this is not struct")
return
}
//获取结构体字段数量
stu_num := v.NumField()
fmt.Println("字段数量是:", stu_num)
//获取结构体方法数量
stu_methom := v.NumMethod()
fmt.Println("方法数量是:", stu_methom)
}
func main() {
var stu student = student{
name: "zhangsan",
age: 20,
score: 50,
}
Test(stu)
}
[Running] go run "f:\goProject\src\dev_code\day23\example5\main\main.go"
字段数量是: 3
方法数量是: 2
[Done] exited with code=0 in 0.592 seconds
获取字段属性值
package main
import (
"fmt"
"reflect"
)
type student struct {
name string
age int
}
//反射来获取结构体中定义的属性值和类型
func Testprint(i interface{}) {
v := reflect.ValueOf(i)
//遍历结构体中所有的属性
for i := 0; i < v.NumField(); i++ {
fmt.Printf("索引:%d,值:%v,类型:%v\n", i, v.Field(i), v.Field(i).Kind())
}
}
func main() {
//实例化
var stu student
stu.name = "zhangsan"
stu.age = 25
Testprint(stu)
}
[Running] go run "f:\goProject\src\dev_code\day23\example9\main\main.go"
索引:0,值:zhangsan,类型:string
索引:1,值:25,类型:int
[Done] exited with code=0 in 0.593 seconds
也可以在cmd命令行中输出
F:\goProject\src\dev_code\day23\example9\main>go run main.go
索引:0,值:zhangsan,类型:string
索引:1,值:25,类型:int
更改属性的值
package main
import (
"fmt"
"reflect"
)
type student struct {
Name string //字段名字首字母需要大写
Age int
}
//更新值
func SetValue(i interface{}, name string) {
v := reflect.ValueOf(i)
vk := v.Kind()
//如果不是指针,而指针指向的类型是结构体,则异常退出
if vk != reflect.Ptr && v.Elem().Kind() == reflect.Struct {
fmt.Println("type err")
return
}
//修改值
v.Elem().Field(0).SetString(name)
//遍历结构体重所有的属性
for i := 0; i < v.Elem().NumField(); i++ {
fmt.Printf("索引:%d,值:%v,类型:%v\n", i, v.Elem().Field(i), v.Elem().Field(i).Kind())
}
}
func main() {
//实例化
var stu student
stu.Name = "zhangsan"
stu.Age = 25
//Testprint(stu)
SetValue(&stu, "lisi")
}
[Running] go run "f:\goProject\src\dev_code\day23\example9\main\main.go"
索引:0,值:lisi,类型:string
索引:1,值:25,类型:int
[Done] exited with code=0 in 0.576 seconds
反射获取原信息
package main
import (
"encoding/json"
"fmt"
"reflect"
)
type student struct {
Name string `json:"name"`
age int
}
//反射来获取结构体中定义的属性值和类型
func Testprint(i interface{}) {
v := reflect.ValueOf(i)
//遍历结构体中所有的属性
for i := 0; i < v.NumField(); i++ {
fmt.Printf("索引:%d,值:%v,类型:%v\n", i, v.Field(i), v.Field(i).Kind())
}
}
func main() {
//实例化
var stu student
stu.Name = "zhangsan"
stu.age = 25
Testprint(stu)
fmt.Println("-----原信息------")
result, _ := json.Marshal(stu)
fmt.Println("json原信息:", string(result))
fmt.Println("-------反射获取原信息----------")
//反射获取属性
st := reflect.TypeOf(stu)
s := st.Field(0)
fmt.Printf("Name原信息名称:%s\n", s.Tag.Get("json"))
}
[Running] go run "f:\goProject\src\dev_code\day24\example1\main\main.go"
索引:0,值:zhangsan,类型:string
索引:1,值:25,类型:int
-----原信息------
json原信息: {"name":"zhangsan"}
-------反射获取原信息----------
Name原信息名称:name
[Done] exited with code=0 in 0.599 seconds
5,函数的反射
示例: Go中函数可以赋值给变量。
package main
import "fmt"
//定义函数
func hello() {
fmt.Println("hello world")
}
func main() {
a := hello
a()
}
[Running] go run "f:\goProject\src\dev_code\day23\example6\main\main.go"
hello world
[Done] exited with code=0 in 0.583 seconds
示例:既然函数可以像普通的类型变量样, 那么在反射机制中就和不同的变量是一样, 在反射中函数和方法的类型(Type)都是reflect.Func,如果要调用函数,通过Value的Call()方法
package main
import (
"fmt"
"reflect"
)
//定义函数
func hello() {
fmt.Println("hello world")
}
func main() {
// a := hello
// a()
//反射使用函数
v := reflect.ValueOf(hello)
//类型判断是否是reflect.func
if v.Kind() == reflect.Func {
fmt.Println("函数")
}
//反射调用函数
v.Call(nil)
}
[Running] go run "f:\goProject\src\dev_code\day23\example6\main\main.go"
函数
hello world
[Done] exited with code=0 in 0.605 seconds
示例:反射调用传参和返回值函数,传参传的是切片返回值也是切片
package main
import (
"fmt"
"reflect"
"strconv"
)
//反射调用传参和返回值函数
func Test(i int) string {
return strconv.Itoa(i)
}
func main() {
v := reflect.ValueOf(Test)
//定义参数切片
params := make([]reflect.Value, 1)
//切片元素赋值20
params[0] = reflect.ValueOf(20)
//反射调函数
result := v.Call(params)
fmt.Printf("result的类型:%T\n", result)
//进行类型的转换切片转换string.[]reflect.Value转换成string
s := result[0].Interface().(string)
fmt.Printf("s的类型:%T,值:%s\n", s, s)
}
[Running] go run "f:\goProject\src\dev_code\day23\example7\main\main.go"
result的类型:[]reflect.Value
s的类型:string,值:20
[Done] exited with code=0 in 0.597 seconds
6,方法反射
反射中方法的调用。函数和方法可以说其实本质上是相同的,只不过方法与一个对象”进行了 “绑定",方法是“对象”的一种行为,这种行为是对于这个对象”的一系列操作, 例如修改"对象的某个属性。 示例:
package main
import (
"fmt"
"reflect"
"strconv"
)
//反射方法
type Student struct {
Name string
Age int
}
//方法
func (s *Student) Setname(name string) {
s.Name = name
}
func (s *Student) Setage(age int) {
s.Age = age
}
func (s *Student) String() string {
return fmt.Sprintf("%p", s) + " name:" + s.Name + " age:" + strconv.Itoa(s.Age)
}
func main() {
//实例化检查student对象内容,用地址
stu := &Student{"zhangsan", 25}
//反射获取值:指针方式
stuv := reflect.ValueOf(&stu).Elem()
fmt.Println("修改前:", stuv.MethodByName("String").Call(nil)[0])
//修改值
p := make([]reflect.Value, 1)
p[0] = reflect.ValueOf("lisi")
//按名称来调用方法Setname
stuv.MethodByName("Setname").Call(p)
p[0] = reflect.ValueOf(35)
stuv.MethodByName("Setage").Call(p)
fmt.Println("修改后:", stuv.MethodByName("String").Call(nil)[0])
}
[Running] go run "f:\goProject\src\dev_code\day24\example2\main\main.go"
修改前: 0xc000004078 name:zhangsan age:25
修改后: 0xc000004078 name:lisi age:35
[Done] exited with code=0 in 0.62 seconds
反射中方法调用:按索引的方式调方法
PS:索引的排序是与方法名字的ASCII阿斯克码名字进行的排序与前后写方法的顺序无关
package main
import (
"fmt"
"reflect"
"strconv"
)
//按索引的方式调用方法
//反射方法
type Student struct {
Name string
Age int
}
//方法
func (s *Student) Setname(name string) {
s.Name = name
}
func (s *Student) Setage(age int) {
s.Age = age
}
func (s *Student) String() string {
return fmt.Sprintf("%p", s) + " name:" + s.Name + " age:" + strconv.Itoa(s.Age)
}
func main() {
//实例化检查student对象内容,用地址
stu := &Student{"zhangsan", 25}
//反射获取值:指针方式
stuv := reflect.ValueOf(&stu).Elem()
//反射获取值:值类型
// stuv:=reflect.ValueOf(stu)
//方式二,按方法的索引调用
fmt.Println("修改前:", stuv.Method(2).Call(nil)[0])
p := make([]reflect.Value, 1)
p[0] = reflect.ValueOf("wangwu")
stuv.Method(1).Call(p)
p[0] = reflect.ValueOf(35)
stuv.Method(0).Call(p)
fmt.Println("修改后:", stuv.Method(2).Call(nil)[0])
}
//索引的排序是与方法名字的ASCII阿斯克码名字进行的排序与前后写方法的顺序无关
[Running] go run "f:\goProject\src\dev_code\day24\example3\main\main.go"