开发者学堂课程【Go语言核心编程 - 面向对象、文件、单元测试、反射、TCP编程:反射的注意事项和细节(2)】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/626/detail/9771
反射的注意事项和细节(2)
内容介绍
一、通过反射来修改变量
二、reflect.Value.Elem 如何理解
一、通过反射来修改变量
1、文字叙述
通过反射的来修改变量,注意当使用 setxxx 方法 来设置需要通过对应的指针类型来完成。这样才能改变传入的变量的值,同时需要使用到 reflect.Value.Elem。
通过反射来修改变量这是一个很重要的细节,比如现在有一个需求就是通过反射来修改变量,想使用 setxxx 方法来设置需要通过对应的指针类型来完成。这样才能改变传入的变量的值,同时需要使用到reflect.Value.Elem。传了一个 int 进去,希望在反射里面把 int 的值改过来。新建一个文件 main.go,想通过反射来修改 num int 的值,然后再去修改 student 这个结构体的值。首先写一个 func reflect01(interface{}),因为前面的部分是一样的,所以把代码拿过来就行。这里肯定是有一个空接口的。先按套路写一个 num,把它定义成 int。这样写是可以更明确一点,也可以直接一个冒号就可以了。reflect01,把这个 num 传进去,这样传进去显然不用多说,前面的 valueof 并不会影响到这里,相当于 b 传过去后并不会影响到这个 num,对此肯定是传了一个地址过去才能用。当传入了一个地址过后很明确的知道 reflect.value 本身是提供了一个方法。这个方法就叫 setstring,好像是通过 setstring 就可以改变值。这个时候来输出这个值 fmt.Println,输入一个 num,一保存就报错了。因为使用了一个与地址无关的值,运行的时候检测不出。这里传入的是一个地址进去,此时是这个类型它本质上为何物。把它打出来这个类型会发现它其实是一个指针。因为这里传的不是 num 而是一个地址,R.val1 的Kind的是 int 类型的。它的类别已经不是一个结构体了,可以看到它是一个 ptr。这个时候只有传这个指针进去才会改变到 num。r.val 的类型已经不再是一个值类型了,而是一个指针类型了。在调 set 的时候它绑定的是 value,它认为就应该是非地址的才能用这个方法。可是现在是个地址就不能用这个方法了。那现在意味着必须把这种地址类型的重新转成非地址的。对此有一个很简单又很重要的方法会大量用到,叫做 Elem。虽然都是 value 但类型是不一样的。Elem 返回 v 持有的接口保管的值的 value 封装,或者是 v 持有的指针指向的值的 value 封装。也就是说 rval.Elem()SetInt(20) 这样就可以了。对 rval.Elem 可以这样理解:这里有一个 num 是 int 类型的9,有一个 ptr 指针是指向 int 的,然后把 num 给它了。当要取一个具体的值时,要返回来再取它的值,是 num2=*ptr 这样去做。可以简单理解成这种写法就相当于取到了指针指向的真正的值。当然改变的时候其实是改变的同一个数据空间。num2=*ptr 就类似于 rval.Elem。rVal 这个地方的作用是要返回 rVal 它的指针指向的具体的值。然后再改变 SetInt。具体的值就是它的空间了。这样一做代码就可以了。这个时候代码不会报错,而且会输出20。在反射应用里面大量用到 Elem。反射能直接改变外面的结构体或者变量的值,因为价值就在这里。此时 num 就变成20了。如果没有这句话就直接报错。因为它使用指针的类型进行处理。如果是改变结构体的值,也是类似这样去处理。当然结构体比普通的数据类型的改变稍微麻烦一些,因为它首先要拿到字段才能改。
2、代码如下:
package main
import(
“
reflect
”
“
fmt
”
)
//通过反射,修改,
//num int 的值
//修改 student 的值
func reflect01(b interface{}){
//2. 获取到 reflect.Value
rval:=reflect.Valueof(b)
//看看 rval 的 Kind 是
fmt.Printf(“rval kind=%v\n”,rval. kind())
//3.rval
rval.Elem().SetInt(20)
}
func main(){
var num int=10
reflect01(&num)
fmt.Println(“num=”,num)//20
//你可以这样理解 rval.Elem()
Num:9
ptr *int=&num
num2 :=*ptr//===类似 rval.Elem()
3、案例如下:
Func testInt(b interface{})
Val: reflect.valueof(b)
Fmt.Printf(“val type=LT/n”,val)
Val.Elem().SetInt(110)
Fmt.Printf(val =%v\n,val)
Func main()
var num int=20
testInt(&num)
Fmt.Println(“num=”,num)
二、reflect.Value.Elem 如何理解
1、第六点其实并不算什么细节,只是告诉如何去理解。比如刚才把 num 反射了一下,反射把地址传给了 fn,fn 就相当于接口拿到的东西。Fn.Elem().SetInt,这个就是改变的 num。
2、代码如下:
func main() {
var num int=100
fn=reflect.Valueof(&)
fn.Elem().SetInt(200)
fmt.Printf(“%v\n”,num)
//fn.Elem() 用于获取指针指向变量,类似
var num=10
var b *int=&num
*
b=3