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

要修改值,必须满足:

  • 可以寻址

    可寻址的类型:

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

1.指针指向的具体元素

需要两步:

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

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

package main

import (
"fmt"
"reflect"
) func main() { a := 1 v := reflect.ValueOf(a) fmt.Println("v Type:", v.Type())
fmt.Println("v CanSet:", v.CanSet()) v = reflect.ValueOf(&a)
fmt.Println("v Type:", v.Type())
fmt.Println("v CanSet:", v.CanSet()) v = v.Elem() // element value
fmt.Println("v Type:", v.Type())
fmt.Println("v CanSet:", v.CanSet()) // set
v.SetInt(2)
fmt.Println("after set, v:", v) newValue := reflect.ValueOf(3)
v.Set(newValue)
fmt.Println("after set, v:", v) }

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

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

输出结果:

v: 1
v Type: int
v CanSet: false
v Type: *int
v CanSet: false
v Type: int
v CanSet: true
after set, v: 2
after set, v: 3

2.slice的元素

需要两步:

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

具体代码如下。

package main

import (
"fmt"
"reflect"
) func main() { a := []int{1,1} v := reflect.ValueOf(a)
fmt.Println("v:", v) fmt.Println("v Type:", v.Type())
fmt.Println("v CanSet:", v.CanSet()) e := v.Index(0)
fmt.Println("e CanSet:", e.CanSet()) e.SetInt(2) fmt.Println("after set:", v)
}

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

接着,修改元素的值。

结果输出:

v: [1 1]
v Type: []int
v CanSet: false
e CanSet: true
after set: [2 1]

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

需要三步:

  • 取结构体地址 v := reflect.ValueOf(&a)
  • 获取结构体的具体值:Elem()
  • 获取结构体的字段:FieldByName()
package main

import (
"fmt"
"reflect"
) type Orange struct {
Size int
} func main() { a := Orange{99} v := reflect.ValueOf(a)
fmt.Println("v:", v) fmt.Println("v Type:", v.Type())
fmt.Println("v CanSet:", v.CanSet()) v = reflect.ValueOf(&a)
fmt.Println("v:", v) fmt.Println("v Type:", v.Type())
fmt.Println("v CanSet:", v.CanSet()) //element
v = v.Elem() size := v.FieldByName("Size")
fmt.Println("size CanSet:", size.CanSet()) size.SetInt(88) fmt.Println("after set:", v) }

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

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

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

输出结果

v: {99}
v Type: main.Orange
v CanSet: false
v: &{99}
v Type: *main.Orange
v CanSet: false
size CanSet: true
after set: {88}

4.可寻址的数组的元素

需要三步:

  • 取数组地址 v := reflect.ValueOf(&a)
  • 获取反射对象中的具体值:Elem()
  • 通过索引获取元素:Index(0)
package main

import (
"fmt"
"reflect"
) func main() { a := [2]int{1,1} v := reflect.ValueOf(a)
fmt.Println("v:", v) fmt.Println("v Type:", v.Type())
fmt.Println("v CanSet:", v.CanSet()) e := v.Index(0)
fmt.Println("e Type:", e.Type())
fmt.Println("e CanSet:", e.CanSet()) v = reflect.ValueOf(&a)
fmt.Println("v:", v) fmt.Println("v Type:", v.Type())
fmt.Println("v CanSet:", v.CanSet()) // element
v = v.Elem()
e = v.Index(0)
fmt.Println("e Type:", e.Type())
fmt.Println("e CanSet:", e.CanSet()) e.SetInt(3) fmt.Println("after set:", v) }

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

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

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

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

输出结果

v: [1 1]
v Type: [2]int
v CanSet: false
e Type: int
e CanSet: false
v: &[1 1]
v Type: *[2]int
v CanSet: false
e Type: int
e CanSet: true
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. subversion(SVN)服务配置及使用方法

      1.安装 yum install httpd httpd-devel subversion mod_dav_svn mod_auth_mysql -y 2.查看版本 svnserve --vers ...

  2. 21、Nginx 常见问题

    1.多个server_name容易产生冲突,会按照如下顺序匹配 1.首先选择所有的字符串完全匹配的server_name.(完全匹配) 2.选择通配符在前面的server_name,如*.bgx.co ...

  3. 月薪 30K Java 程序员,需要掌握哪些技术?

    转载自:Java3y 1-5年的Java程序员,薪资区间大致是在15-25K左右,那有没有可能提前达到30K的薪资呢?有人说这只能是大企业或者互联网企业工程师才能拿到.也许是的,小公司或者非互联网企业 ...

  4. deep_learning_Function_tf.train.ExponentialMovingAverage()滑动平均

    近来看batch normalization的代码时,遇到tf.train.ExponentialMovingAverage()函数,特此记录. tf.train.ExponentialMovingA ...

  5. centos6.8 上传文件到amazon s3

    centos6.8 上传文件到amazon s3 0.参考 AWS CLI Cinnabd Reference Possible to sync a single file with aws s3 s ...

  6. 华为ensp问题:云映射本地网卡,直连路由器可以ping通,pc却不行?

    拓扑图:cloud 云映射本机物理网卡:192.168.56.1     R1可以Ping通,所有Pc都不行,路由表也存在路由信息,不知道什么问题?

  7. iscsi原理

    iscsi原理 一,[名词解释] SCSI:小型计算机系统接口,SCSI作为i输入/输出接口, FC:光纤通道 DAS:直连式存储,指将存储设备通过SCSI接口或光纤通道直接连到一台计算机上. NAS ...

  8. Codeforces Round #581 (Div. 2) B. Mislove Has Lost an Array (贪心)

    B. Mislove Has Lost an Array time limit per test1 second memory limit per test256 megabytes inputsta ...

  9. poj1015 Jury Compromise[背包]

    每一件物品有两个属性.朴素思想是把这两种属性都设计到状态里,但空间爆炸.又因为这两个属性相互间存在制约关系(差的绝对值最小),不妨把答案设计入状态中,设$f[i][j]$选$i$个人,两者之差$j$. ...

  10. centos后台运行程序

    putty等软件运行,python程序:python p.py    只要一关闭putty, 程序就结束.如何让退出终端或关闭终端电脑,还能让程序在服务器后台运行Python. 关键的命令:nohup ...