不是所有的反射值都可以修改。对于一个反射值是否可以修改,可以通过CanSet()进行检查。

要修改值,必须满足:

  • 可以寻址

    可寻址的类型:

    • 指针指向的具体元素
    • slice的元素
    • 可寻址的结构体的字段(指向结构体的指针)
    • 可寻址的数组的元素(指向数组的指针)
  • 不是结构体没有导出的字段

1.指针指向的具体元素

需要两步:

  • 取地址:v := reflect.ValueOf(&x)
  • 取得具体值 v=v.Elem()

下面通过一个整型变量的赋值进行说明。

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. func main() {
  7. a := 1
  8. v := reflect.ValueOf(a)
  9. fmt.Println("v Type:", v.Type())
  10. fmt.Println("v CanSet:", v.CanSet())
  11. v = reflect.ValueOf(&a)
  12. fmt.Println("v Type:", v.Type())
  13. fmt.Println("v CanSet:", v.CanSet())
  14. v = v.Elem() // element value
  15. fmt.Println("v Type:", v.Type())
  16. fmt.Println("v CanSet:", v.CanSet())
  17. // set
  18. v.SetInt(2)
  19. fmt.Println("after set, v:", v)
  20. newValue := reflect.ValueOf(3)
  21. v.Set(newValue)
  22. fmt.Println("after set, v:", v)
  23. }

定义一个整型变量,得到反射值,检查是否可以修改。

接着,通过反射获取整型变量地址的反射值,再通过Elem()得到指针指向的具体对象,这样就可以修改值。

输出结果:

  1. v: 1
  2. v Type: int
  3. v CanSet: false
  4. v Type: *int
  5. v CanSet: false
  6. v Type: int
  7. v CanSet: true
  8. after set, v: 2
  9. after set, v: 3

2.slice的元素

需要两步:

  • 取切片:v := reflect.ValueOf(s)
  • 获取切片的元素 e := v.Index(0)

具体代码如下。

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. func main() {
  7. a := []int{1,1}
  8. v := reflect.ValueOf(a)
  9. fmt.Println("v:", v)
  10. fmt.Println("v Type:", v.Type())
  11. fmt.Println("v CanSet:", v.CanSet())
  12. e := v.Index(0)
  13. fmt.Println("e CanSet:", e.CanSet())
  14. e.SetInt(2)
  15. fmt.Println("after set:", v)
  16. }

定义一个slice,得到反射值,从slice 的反射值中元素,

接着,修改元素的值。

结果输出:

  1. v: [1 1]
  2. v Type: []int
  3. v CanSet: false
  4. e CanSet: true
  5. after set: [2 1]

3.可寻址的结构体的字段

需要三步:

  • 取结构体地址 v := reflect.ValueOf(&a)
  • 获取结构体的具体值:Elem()
  • 获取结构体的字段:FieldByName()
  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. type Orange struct {
  7. Size int
  8. }
  9. func main() {
  10. a := Orange{99}
  11. v := reflect.ValueOf(a)
  12. fmt.Println("v:", v)
  13. fmt.Println("v Type:", v.Type())
  14. fmt.Println("v CanSet:", v.CanSet())
  15. v = reflect.ValueOf(&a)
  16. fmt.Println("v:", v)
  17. fmt.Println("v Type:", v.Type())
  18. fmt.Println("v CanSet:", v.CanSet())
  19. //element
  20. v = v.Elem()
  21. size := v.FieldByName("Size")
  22. fmt.Println("size CanSet:", size.CanSet())
  23. size.SetInt(88)
  24. fmt.Println("after set:", v)
  25. }

定义一个结构体变量,首先反射变量,检查是否可以修改值。

接着,使用变量地址进行反射,通过Elem()获取指针指向的具体值。

最后,获取结构体的字段,并修改值。

输出结果

  1. v: {99}
  2. v Type: main.Orange
  3. v CanSet: false
  4. v: &{99}
  5. v Type: *main.Orange
  6. v CanSet: false
  7. size CanSet: true
  8. after set: {88}

4.可寻址的数组的元素

需要三步:

  • 取数组地址 v := reflect.ValueOf(&a)
  • 获取反射对象中的具体值:Elem()
  • 通过索引获取元素:Index(0)
  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. func main() {
  7. a := [2]int{1,1}
  8. v := reflect.ValueOf(a)
  9. fmt.Println("v:", v)
  10. fmt.Println("v Type:", v.Type())
  11. fmt.Println("v CanSet:", v.CanSet())
  12. e := v.Index(0)
  13. fmt.Println("e Type:", e.Type())
  14. fmt.Println("e CanSet:", e.CanSet())
  15. v = reflect.ValueOf(&a)
  16. fmt.Println("v:", v)
  17. fmt.Println("v Type:", v.Type())
  18. fmt.Println("v CanSet:", v.CanSet())
  19. // element
  20. v = v.Elem()
  21. e = v.Index(0)
  22. fmt.Println("e Type:", e.Type())
  23. fmt.Println("e CanSet:", e.CanSet())
  24. e.SetInt(3)
  25. fmt.Println("after set:", v)
  26. }

定义一个数组变量,首先反射变量,检查是否可以修改值。

接着,取数组中的元素,检查是否可以修改值。

使用数组的地址进行反射,通过Elem()获取指针指向的具体值。

最后,获取数组中的元素,并修改值。

输出结果

  1. v: [1 1]
  2. v Type: [2]int
  3. v CanSet: false
  4. e Type: int
  5. e CanSet: false
  6. v: &[1 1]
  7. v Type: *[2]int
  8. v CanSet: false
  9. e Type: int
  10. e CanSet: true
  11. after set: [3 1]

golang 通过reflect反射修改值的更多相关文章

  1. golang:reflect反射

    因为之前一直以C++为主要开发语言,所以刚接触go语言中的reflect时感觉很懵逼,因此决定找资料彻底学习一下. 到底反射是什么? https://blog.golang.org/laws-of-r ...

  2. golang基础--reflect反射

    反射的知识点比较晦涩,后期会对此知识点展开深入的分析及示例代码展示 反射可达大提高程序的灵活性,使得inferface{}有更大的发挥余地 反射使用TypeOf和ValueOf函数从接口中获取目标对象 ...

  3. golang 使用reflect反射结构体

    "反射结构体"是指在程序执行时,遍历结构体中的字段以及方法. 1.反射结构体 下面使用一个简单的例子说明如何反射结构体. 定义一个结构体,包括3个字段,以及一个方法. 通过refl ...

  4. go中的关键字-reflect 反射

    1. 什么是反射 Golang提供了一种机制,在编译时不知道类型的情况下,可更新变量.运行时查看值.调用方法以及直接对他们的布局进行操作的机制,称为反射. 2. 反射的使用 2.1 获取变量内部信息 ...

  5. golang中的反射reflect详解

    先重复一遍反射三定律: 1.反射可以将"接口类型变量"转换为"反射类型对象". 2.反射可以将"反射类型对象"转换为"接口类型变量 ...

  6. Golang 接口与反射知识要点

    目录 Golang 接口与反射知识要点 1. 接口类型变量 2. 类型断言 3. 鸭子类型 4. 反射机制 5. reflect 包 TypeOf().ValueOf() Type().Kind() ...

  7. Golang通脉之反射

    什么是反射 官方关于反射定义: Reflection in computing is the ability of a program to examine its own structure, pa ...

  8. JAVA 构造器, extends[继承], implements[实现], Interface[接口], reflect[反射], clone[克隆], final, static, abstrac

    记录一下: 构造器[构造函数]: 在java中如果用户编写类的时候没有提供构造函数,那么编译器会自动提供一个默认构造函数.它会把所有的实例字段设置为默认值:所有的数字变量初始化为0;所有的布尔变量设置 ...

  9. mybatis批量更新两种方式:1.修改值全部一样 2.修改每条记录值不一样

    Mybatis批量更新数据 mybatis批量更新两种方式:1.修改值全部一样 2.修改每条记录值不一样 mybatis批量更新两种方式:1.修改值全部一样 2.修改每条记录值不一样 mybatis批 ...

随机推荐

  1. docker 环境安装

    centos7下安装docker.docker-compose 参考文档:https://docs.docker.com/ 一.安装docker 1).Docker 要求 CentOS 系统的内核版本 ...

  2. CentOS7 SVN基本配置

    开机自启指令如下 systemctl enable svnserve.service 对应可执行脚本文件路径 vim /etc/sysconfig/svnserve 查看状态: ps -ef|grep ...

  3. 运行期优化 Java内存模型与线程 线程安全与优化

  4. Storm项目开发纪要

    1.POM引用storm-core和javax.servlet-api这两个组件,如果本地模式跑拓扑,要把<scope>provided</scope>去掉:如果远程发布运行, ...

  5. jQuery获取当前按钮的id

    function test(e) { $(e.target).attr('id') } // 记得带上点击事件

  6. 利用nethogs查看哪些进程占用网络带宽

    一.安装nethogs centos6版本安装: 1.安装依赖包 [root@hlsms-fensheng- ~]# yum install ncurses* 已加载插件:fastestmirror, ...

  7. double to long

    obj to double obj to long instance of Bigdecimal public static void main(String[] args) throws Parse ...

  8. 使用maven简单搭建Spring mvc + redis缓存

    注:此文参考并整合了网上的文章 <spring缓存机制>:http://blog.csdn.net/sidongxue2/article/details/30516141 <配置 S ...

  9. 我说CMMI之七:需求管理过程域--转载

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/dylanren/article/deta ...

  10. html中表单提交

    表单提交代码 1.源代码分析 <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...