隐藏页面特效

反射

1|0反射


package main import ( "fmt" "reflect" ) type Student struct { name string } type MyInt int func main() { /*Type的主要方法 Kind()返回一个常量,表示具体类型的底层类型 Elem()返回指针、数组、切片、字典、通道等类型 */ /*Value的主要方法 Kind()返回一个常量,表示具体类型的底层类型 Type()返回具体类型所对应的reflect.Type(静态类型) */ /* 在go语言中,静态类型就是变量声明时赋予的类型,也就是在发射中reflect.Type对应的值,而Kind()对应的是基础类型。 Kind()大概会返回切片、字典、指针、结构体、接口、字符串、数组、函数、整形或其他基础类型。如下面代码中Kind() 返回结构体:fmt.Println(p.Kind()),而Type()返回静态类型名Student:fmt.Println(p.Type()).MyInt是静态类型 而int是它的基础类型。 Type()返回的是静态类型,而Kind()返回的是基础类型 */ var a int = 9 v := reflect.ValueOf(a) //返回Value类型对象,值为9 t := reflect.TypeOf(a) //返回Type类型对象,值为int fmt.Println(v, t, v.Type(), v.Kind(), t.Kind()) //Kind()返回底层基础类型 /* 9 int int int int */ var mi MyInt = 99 mv := reflect.ValueOf(mi) //返回Value类型对象,值为99 mt := reflect.TypeOf(mi) // 返回Type类型对象,值为MyInt fmt.Println(mv, mt, mv.Type(), mv.Kind(), mt.Kind()) //Kind()返回底层基础类型 /* 99 main.MyInt main.MyInt int int */ var b [5]int = [5]int{5, 6, 7, 8} fmt.Println(reflect.TypeOf(b), reflect.TypeOf(b).Kind(), reflect.TypeOf(b).Elem()) /* [5]int array int */ var Pupil Student p := reflect.ValueOf(Pupil) //使用ValueOf获得结构体的Value对象 fmt.Println(p.Type(), p.Kind()) /* main.Student struct */ }

2|0反射的应用


/*反射的应用 (1)通过反射可以修改对象 通过反射可以修改对象,但对象必须是可寻址的(addressable)。简单说,如果想通过反射修改对象,就需要把想修改 对象的指针传递过来。如果对象不能被寻址,那就是不可写的。可写性是反射类型变量的一个属性,但不是所有反射类型 变量都拥有这个属性,所以通过反射修改原对象,需要判断其可写性,也就是可寻址。 实际上要修改的是指针指向的数据,需要调用Value类型的Elem()方法。Elem()方法能够对指针进行间接引用,将结果 存储到reflect.Value类型对象中。 v := reflect.Value.Elem() //表示获取原始值对应的反射对象 通过CanSet()方法来判断原始反射对象v reflect.Value是否可写,CanAddr()方法判断它是否可被取地址。这里的v是通过 Elem()得到的。CanSet()和CanAddr()这两个方法的签名如下: func (v Value)CanAddr() func (v Value)CanSet() bool */ var a int = 9 v := reflect.ValueOf(a) // 返回Value类型对象,值为9 t := reflect.TypeOf(a) // 返回Type类型对象,值为int fmt.Println(v.Type(), t.Kind(), reflect.ValueOf(&a).Elem()) /* int int 9 */ fmt.Println(reflect.ValueOf(a).CanSet(), reflect.ValueOf(a).CanAddr()) /* false false */ fmt.Println(reflect.ValueOf(&a).CanSet(), reflect.ValueOf(&a).CanAddr()) /* false false */ pa := reflect.ValueOf(&a).Elem() // reflect.Value.Elem()表示获取原始值对应的反射对象 fmt.Println(pa.CanSet(), pa.CanAddr()) /* true true */ pa.SetInt(100) fmt.Println(pa) /* 100 */ var Pupil Student = Student{"jim", 8} Pupilv := reflect.ValueOf(Pupil) //使用ValueOf()获取结构体的Value对象 fmt.Println(Pupilv.Type(), Pupilv.Kind()) /* main.Student struct */ p := reflect.ValueOf(&Pupil).Elem() //获取原始值对应的反射对象 fmt.Println(p.CanSet(), p.CanAddr()) /* true true */ // p.Field(0).SetString("Mike") 报错,原因是字段需要大写(需可以被外部包调用) p.Field(1).SetInt(10) fmt.Println(p) /* {jim 10} */ /* 要通过反射的方式来修改对象,重点是通过方法Elem()获取原始值对应的反射对象。虽然反射可以越过go语言的导出规则 的限制读取结构中未导出的成员,但不能修改他们。因为一个结构体中只有被导出(可被外部包调用)的字段才是可写的。 reflect.ValueOf(&a)得到的是原始变量a的指针地址,这个指针地址再通过Elem()方法得到反射对象。 */ /* 结构体中有tag标签,通风反射可获取结构体成员变量的tag信息。 type Student struct { name string Age int `json:"years"` } */ var s Student = Student{"joke", 18} setStudent := reflect.ValueOf(&s).Elem() sSAge, _ := setStudent.Type().FieldByName("Age") fmt.Println(sSAge.Tag.Get("json")) /* years */ /* (2)通过反射可以创建基础类型和用户自定义类型变量 除了可以通过反射创建基础类型和用户自定义类型,还可以使用反射来创建切片,字典,通道,甚至包括函数类型。常见函数有: reflect.Makeslice(),reflect.Makemap()和reflect.Makechan() */ /* 想创建变量,需要先确定类型。下面的代码中根据reflect.Type(t)得到t的静态类型,接着使用reflect.New(vartype)生成了新变量。 新变量通过方法Elem()获取的反射对象来设置变量值。最后使用Elem().interface()来反引用reflect的指针,得到新变量的值。 */ /* t := 9 // 反射创建int变量 varType := reflect.TypeOf(t) v1 := reflect.New(varType) v1.Elem().SetInt(1) varNew := v1.Elem().Interface() fmt.Printf("指针:%d, 值:%d\n", v1, varNew) // 反射创建map slice newSlice := make([]int, 5) newmap := make(map[string]int) sliceType := reflect.TypeOf(newSlice) mapType := reflect.TypeOf(newmap) // 创建新值 ReflectSlice := reflect.MakeSlice(sliceType, 5, 5) Reflectmap := reflect.MakeMap(mapType) // 使用新创建的变量 V := 99 SliceV := reflect.ValueOf(V) ReflectSlice = reflect.Append(ReflectSlice, SliceV) intSlice := ReflectSlice.Interface().([]int) fmt.Println("Slice:", intSlice) Key := "Rose" Value := 999 MapKey := reflect.ValueOf(Key) MapValue := reflect.ValueOf(Value) Reflectmap.SetMapIndex(MapKey, MapValue) mapStringInt := Reflectmap.Interface().(map[string]int) fmt.Println("Map:", mapStringInt) /* 指针:824633811096, 值:1 Slice: [0 0 0 0 0 99] Map: map[Rose:999] */ }

3|0通过反射机制,能对一个结构体类型的大致结构如方法、字段的情况有较为全面的了解


package main import ( "fmt" "reflect" ) type ss struct { int string bool float64 } func (s ss) Method(i int) string { return "结构体方法1" } func (s *ss) Method2(i int) string { return "结构体方法2" } var ( structValue = ss{ // 结构体 20, "结构体", false, 64.0, } ) func main() { // 通过反射机制,能对一个结构体类型的大致结构如方法、字段的情况有较为全面的了解 fmt.Println("-------------引用------------") v := reflect.ValueOf(&structValue) fmt.Println(v.String()) // 反射值的字符串形式 fmt.Println(v.Type()) //反射值的类型 fmt.Println(v.Kind()) //反射值的类别 fmt.Println(v.CanAddr()) //是否可以获取地址 fmt.Println(v.CanSet()) //是否可以修改 if v.CanAddr() { fmt.Println(v.Addr()) //获取地址 fmt.Println(v.UnsafeAddr()) // 获取自由地址 } // 获取方法数量 fmt.Println("可用方法数量:", v.NumMethod()) if v.NumMethod() > 0 { i := 0 for ; i < v.NumMethod()-1; i++ { fmt.Println(v.Method(i).String()) } fmt.Println(v.Method(i).String()) // 通过名称获取方法 fmt.Println(v.MethodByName("Method1").String()) fmt.Println(v.MethodByName("Method2").String()) } fmt.Println("------------------值变量------------------") v = reflect.ValueOf(structValue) fmt.Println(v.String()) //反射值的字符串形式 fmt.Println(v.Type()) // 反射值的类型 fmt.Println(v.Kind()) // 反射值的类别 fmt.Println(v.CanAddr()) //是否可以获取地址 fmt.Println(v.CanSet()) //是否可以修改 if v.CanAddr() { fmt.Println(v.Addr()) //获取地址 fmt.Println(v.UnsafeAddr()) //获取自由地址 } // 获取方法数量 fmt.Println(v.NumMethod()) fmt.Println(reflect.ValueOf(&structValue).NumMethod()) if v.NumMethod() > 0 { i := 0 for ; i < v.NumMethod()-1; i++ { fmt.Println(v.Method(i).String()) } fmt.Println(v.Method(i).String()) // 通过名称获取方法 fmt.Println(v.MethodByName("Method1").String()) fmt.Println(v.MethodByName("Method2").String()) } switch v.Kind() { // 结构体 case reflect.Struct: fmt.Println("-----------结构体----------") // 获取字段个数 fmt.Println(v.NumField()) if v.NumField() > 0 { var i int //遍历结构体字段 for i = 0; i < v.NumField()-1; i++ { field := v.Field(i) //获取结构体字段 fmt.Println(field.Type(), field.String()) } field := v.Field(i) // 获取结构体字段 fmt.Println(field.Type(), field.String()) // 通过名称查找字段 if v := v.FieldByName("ptr"); v.IsValid() { fmt.Println(v.Type().Name()) } // 通过函数查找字段 v := v.FieldByNameFunc(func(s string) bool { return len(s) > 3 }) if v.IsValid() { fmt.Println(v.Type().Name()) } } } } /* -------------引用------------ <*main.ss Value> *main.ss ptr false false 可用方法数量: 2 <func(int) string Value> <func(int) string Value> <invalid Value> <func(int) string Value> ------------------值变量------------------ <main.ss Value> main.ss struct false false 1 2 <func(int) string Value> <invalid Value> <invalid Value> -----------结构体---------- 4 int <int Value> string 结构体 bool <bool Value> float64 <float64 Value> */

__EOF__

本文作者404 Not Found
本文链接https://www.cnblogs.com/weiweivip666/p/16141926.html
关于博主:可能又在睡觉
版权声明:转载请注明出处
声援博主:如果看到我睡觉请喊我去学习
posted @   我在路上回头看  阅读(62)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示