反射的注意事项和细节(2) | 学习笔记

简介: 快速学习反射的注意事项和细节(2)

开发者学堂课程【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

相关文章
|
编译器 Scala 开发者
函数使用注意事项和细节2|学习笔记
快速学习函数使用注意事项和细节2。
|
Scala 开发者
包对象注意事项和细节说明|学习笔记
快速学习包对象注意事项和细节说明。
包对象注意事项和细节说明|学习笔记
|
Scala 开发者
覆写字段注意事项和细节说明2|学习笔记
快速学习覆写字段注意事项和细节说明2。
104 0
覆写字段注意事项和细节说明2|学习笔记
|
Java 编译器 Scala
函数使用注意事项和细节3|学习笔记
快速学习函数使用注意事项和细节3。
|
Java 程序员 Scala
抽象类使用注意事项和细节|学习笔记
快速学习抽象类使用注意事项和细节。
|
Java 编译器 Scala
函数使用注意事项和细节1|学习笔记
快速学习函数使用注意事项和细节1。
|
网络协议 测试技术 Go
反射的注意事项和细节(1) | 学习笔记
快速学习反射的注意事项和细节(1)
|
Java 程序员 编译器
覆写字段注意事项和细节说明1|学习笔记
快速学习覆写字段注意事项和细节说明1。
106 0
|
Java Scala 开发者
封装注意事项|学习笔记
快速学习封装注意事项。
107 0
|
Go 开发者
函数注意事项和细节(3) | 学习笔记
简介:快速学习函数注意事项和细节(3)