目录
reflect
1. reflect.TypeOf,获取变量的类型,返回reflect.Type类型
2. reflect.ValueOf,获取变量的值,返回reflect Value类型
3. reflect.Value.Kind,获取变量的类别,返回一个常量
4. reflect.Value.Interface(),转换成interface()类型
示例 获取变量类型
package main
import (
"fmt"
"reflect"
)
func Test(i interface{}) {
//反射获取类型
var t = reflect.TypeOf(i)
fmt.Println("类型:", t)
//反射数据值
var v = reflect.ValueOf(i)
fmt.Println("值:", v)
}
func main() {
Test(`
her
his
10
`)
Test(10)
}
运行结果
类型: string
值:
her
his
10
类型: int
值: 10
获取变量类别
package main
import (
"fmt"
"reflect"
)
//定义结构体
type Student struct {
Name string
Age int
}
//反射
func Test(i interface{}) {
//类型
t := reflect.TypeOf(i)
fmt.Println("类型:", t)
//类别
v := reflect.ValueOf(i).Kind()
// c := v.Kind()
// fmt.Println("类别:",c)
fmt.Println("类别:", v)
}
func main() {
var stu = Student{
Name: "张三",
Age: 20,
}
Test(stu)
fmt.Println("---------------------")
var num = 10
Test(num)
}
运行结果
类型: main.Student
类别: struct
---------------------
类型: int
类别: int
示例,断言处理类型转化
package main
import (
"fmt"
"reflect"
)
/*结合断言*/
//定义结构体
type Student struct {
Name string
Age int
}
//反射
func Test(i interface{}) {
//类型
t := reflect.TypeOf(i)
fmt.Println("类型:", t)
//类别
v := reflect.ValueOf(i)
c := v.Kind()
fmt.Println("类别:", c)
fmt.Printf("v的类型:%T\n", v)
fmt.Printf("c的类型:%T\n", c)
//转化为接口
c1 := v.Interface()
fmt.Printf("c1的类型为:%T\n", c1)
//断言处理
stu, ok := c1.(Student)
if ok {
fmt.Printf("stu结构:%v,stu的类型:%T\n", stu, stu)
}
}
func main() {
var stu = Student{
Name: "张三",
Age: 20,
}
Test(stu)
fmt.Println("---------------------")
}
运行结果
类型: main.Student
类别: struct
v的类型:reflect.Value
c的类型:reflect.Kind
c1的类型为:main.Student
stu结构:{张三 20},stu的类型:main.Student
---------------------
ValueOf
获取变量值
reflect.valueOf(x).Float()
reflect.valueOf(x).Int()
reflect.valueOf(x).String()
reflect.valueOf(x).Boo1()
示例:类型转换
package main
import (
"fmt"
"reflect"
)
func Test(i interface{}) {
a := reflect.ValueOf(i)
fmt.Printf("类型:%T\n", a)
//转化指定类型
t := a.String()
fmt.Printf("t的类型:%T\n", t)
}
func main() {
//类型不同会报错
var num = "hello"
Test(num)
}
运行结果
类型:reflect.Value
t的类型:string
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)
fmt.Printf("更改前的类型为:%T,值为:%d\n", v, v)
reslut := v.Int()
fmt.Printf("更改后的类型为%T,值为:%d", reslut, reslut)
}
func main() {
var num = 10
Test(num)
}
运行结果是,很明显是地址的原因,找不地址
panic: reflect: reflect.Value.SetInt using unaddressable value
goroutine 1 [running]:
正确应该这样写
package main
import (
"fmt"
"reflect"
)
func Test(i interface{}) {
v := reflect.ValueOf(i)
//更新值,需要value的地址,否则会报错 Elem()相当于指针
v.Elem().SetInt(100)
fmt.Printf("更改前的类型为:%T\n", v)
reslut := v.Elem().Int()
fmt.Printf("更改后的类型为%T,值为:%d", reslut, reslut)
}
func main() {
var num = 10
Test(&num)
}
运行结果
更改前的类型为:reflect.Value
更改后的类型为int64,值为:100
结构体反射
示例:反射出结构体数量和方法数量
package main
import (
"fmt"
"reflect"
)
//结构体反射
//定义结构体
type Students struct {
Name string
Age int
sex string
}
//方法
func (s Students) Run() {
fmt.Println("正在跑")
}
func (s Students) Sleep() {
fmt.Println("正在休息")
}
func Test(i interface{}) {
v := reflect.ValueOf(i)
//类别判断
if v.Kind() != reflect.Struct {
fmt.Println("不是struc类型")
return
}
//获取结构体字段
stu_num := v.NumField()
fmt.Printf("字段数量:%d\n", stu_num)
//获取方法
stu_men := v.NumMethod()
fmt.Println("方法数量", stu_men)
}
func main() {
//初始化结构体
var stu = Students{
Name: "张三",
Age: 20,
sex: "men",
}
Test(stu)
}
运行结果
字段数量:3
方法数量 2
反射获取结构体中的属性值和类型
package main
import (
"fmt"
"reflect"
)
type Students struct {
Name string
Age int
sex string
}
//反射获取结构体中的属性值和类型
func Test(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 v = Students{
Name: "张三",
Age: 18,
sex: "男",
}
Test(v)
}
运行结果
索引:0,值:张三 类型: string
索引:1,值:18 类型: int
索引:2,值:男 类型: string
更改结构体属性值
package main
import (
"fmt"
"reflect"
)
type Students struct {
Name string
Age int
sex string
}
//反射获取结构体中的属性值和类型
func Test(i interface{}, name string) {
v := reflect.ValueOf(i)
vk := v.Kind()
//判断是否为指针,如果不是指针而是指向结构体,则返回异常
if vk != reflect.Ptr && v.Elem().Kind() == reflect.Struct {
fmt.Println("error message")
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 v = Students{
Name: "张三",
Age: 18,
sex: "男",
}
Test(&v, "李四")
}
运行结果
索引:0,值:李四 类型: string
索引:1,值:18 类型: int
索引:2,值:男 类型: string
反射实现Tag原信息
package main
import (
"encoding/json"
"fmt"
"reflect"
)
type Students struct {
Name string `json:"stu_name" `
Age int
sex string
}
//反射获取结构体中的属性值和类型
func Test(i interface{}, name string) {
v := reflect.ValueOf(i)
vk := v.Kind()
//判断是否为指针,如果不是指针而是指向结构体,则返回异常
if vk != reflect.Ptr && v.Elem().Kind() == reflect.Struct {
fmt.Println("error message")
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 v = Students{
Name: "张三",
Age: 18,
sex: "男",
}
Test(&v, "李四")
fmt.Println("-----------------原信息------------------")
//Tag原信息
result, _ := json.Marshal(v)
fmt.Println("JSON原信息", string(result))
fmt.Println("----------------反射实现原信息---------------")
//反射获取属性类型
re := reflect.TypeOf(v)
//取索引为0的属性赋予给s
s := re.Field(0)
fmt.Printf("Name原信息名称:%s\n", s.Tag.Get("json"))
}
运行结果
索引:0,值:李四 类型: string
索引:1,值:18 类型: int
索引:2,值:男 类型: string
-----------------原信息------------------
JSON原信息 {"stu_name":"李四","Age":18}
----------------反射实现原信息---------------
Name原信息名称:stu_name
函数反射
示例:GO函数可以赋值给变量
package main
import "fmt”
func Hello(){
fmt.Printlnt"hello world")
}
func main(){
//通数可以赋值给变量
a :=Hello
a()
}
运行结果
hello world
Value的Call()方法
示例:既然函数可以像普通的类型变量一样,那么在反射机制中就和不同的变量是一样,在反射中函数和方法的类型(Type)都是reflect.Func,如果要调用函数,通过Value的Call()方法
package main
import (
"fmt"
"reflect"
)
//函数反射
func Helle() {
fmt.Println("hello world")
}
func main() {
v := reflect.ValueOf(Helle)
//判断类型是否为reflect.Func类型
if v.Kind() == reflect.Func {
fmt.Println("函数")
}
//反射调用函数
v.Call(nil)
}
运行结果
函数
hello world
Value的Call()方法的参数是一个Value 的islice,对应的反射函数类型的参数,返回值也是一个Value的 slice,同样对应反射函数类型的返回值。
示例
package main
import (
"fmt"
"reflect"
"strconv"
)
//反射调用函数带参和返回值
func Test(i int) string {
return strconv.Itoa(i)
}
func main() {
v := reflect.ValueOf(Test)
//定义参数切片
scilt := make([]reflect.Value, 1)
//切片赋值
scilt[0] = reflect.ValueOf(10)
//反射调用函数
reslut := v.Call(scilt)
fmt.Printf("类型为:%T\n", reslut)
//类型断言,[]reflect.Value切片转换string
var s = reslut[0].Interface().(string)
fmt.Printf("s类型为:%T\n值为:%s", s, s)
}
运行结果
类型为:[]reflect.Value
s类型为:string
值为:10
方法反射
反射中方法的调用。函数和方法可以说其实本质上是相同的,只不过方法与一个"对象”进行了"绑定”,方法是“对象―的一种行为,这种行为是对于这个“对象”的一系列操作,例如修改“对象"的某个属性。
package main
import (
"fmt"
"reflect"
"strconv"
)
type Students struct {
Name string
Age int
}
//方法
func (s *Students) SetName(name string) {
s.Name = name
}
func (s *Students) SetAge(age int) {
s.Age = age
}
func (s *Students) String() string {
return fmt.Sprintf("地址%p", s) + ",Name:" + s.Name + ",Age:" + strconv.Itoa(s.Age)
}
func main() {
//实例化
stu := &Students{"zhangsan", 20}
//反射获取值,指针方式
stuV := reflect.ValueOf(&stu).Elem()
//也可以使用非指针
//stuV := reflect.ValueOf(stu)
//修改前
fmt.Println("修改前", stuV.MethodByName("String").Call(nil)[0])
//修改值
Slice := make([]reflect.Value, 1)
Slice[0] = reflect.ValueOf("李四")
stuV.MethodByName("SetName").Call(Slice)
Slice[0] = reflect.ValueOf(23)
stuV.MethodByName("SetAge").Call(Slice)
fmt.Println("修改后", stuV.MethodByName("String").Call(nil)[0])
}
运行结果
修改前 地址0xc000004078,Name:zhangsan,Age:20
修改后 地址0xc000004078,Name:李四,Age:23
第二种方式,使用索引
package main
import (
"fmt"
"reflect"
"strconv"
)
type Students struct {
Name string
Age int
}
//方法
func (s *Students) SetName(name string) {
s.Name = name
}
func (s *Students) SetAge(age int) {
s.Age = age
}
func (s *Students) String() string {
return fmt.Sprintf("地址%p", s) + ",Name:" + s.Name + ",Age:" + strconv.Itoa(s.Age)
}
func main() {
//实例化
stu := &Students{"zhangsan", 20}
//反射获取值,指针方式
stuV := reflect.ValueOf(&stu).Elem()
//修改前
fmt.Println("修改前", stuV.Method(2).Call(nil)[0])
//修改值
//索引的大小根据AScll码排序
Slice := make([]reflect.Value, 1)
Slice[0] = reflect.ValueOf("李四")
stuV.Method(1).Call(Slice)
Slice[0] = reflect.ValueOf(23)
stuV.Method(0).Call(Slice)
fmt.Println("修改后", stuV.MethodByName("String").Call(nil)[0])
}
运行结果
修改前 地址0xc000004078,Name:zhangsan,Age:20
修改后 地址0xc000004078,Name:李四,Age:23