Golang反射修改变量值
1. 前言
前面的随笔Golang反射获取变量类型和值分享了如何通过反射获取变量的类型和值,
也就是Golang反射三大定律中的前两个,即从interface{}到反射对象和从反射对象到interface{}。
这篇随笔主要分享通过反射修改各种类型变量值的方法。
2. 判断是否可修改
reflect提供func (v Value) CanSet() bool判断对象值是否修改。
一般情况下,通过反射修改变量值,需要满足以下两个条件。
2.1 该值是可寻址的
类似函数传参,如果需要在函数内修改入参数的内容,那么就需要传引用,而不是传值。
函数内修改入参指向的内容,才能将修改效果“带出”该函数的作用域。
同理,反射修改变量的值,应当是可以寻址的,修改的是反射对象指向的数据内容,
因此,通过反射函数func ValueOf(i any) Value
- 入参
i是引用时,i指向的内容可寻址,因此返回参数Value不可修改,Value.Elem可修改。 - 入参
i是地址时,返回参数Value可修改。 - 入参
i是引用地址时,返回参数Value及Value.Elem均可修改。
上述三种情况如下图所示,经过寻址的内容才有可能是可修改的。

2.2 该值是可导出的
这个主要是针对结构体的成员,该成员的字段名的首字母需要是大写,即是“public”的。
3. 修改slice
slice是引用类型,slice的数据结构如下图所示,通过反射可以修改slice指向的内容。

修改指定下标的数据内容,并且数据类型需要和修改前一只,否则会panic。
func main() {
s := []int{1, 2, 3}
valueS := reflect.ValueOf(s)
// slice 是否可修改 不可整体修改
fmt.Printf("valueS Kind:%v CanSet:%v Index(0).CanSet:%v\n", valueS.Kind(), valueS.CanSet(), valueS.Index(0).CanSet())
// 修改指定下标的元素值
valueS.Index(0).Set(reflect.ValueOf(10))
valueS.Index(1).SetInt(20)
fmt.Printf("after edit:%v\n", s)
// panic: reflect: call of reflect.Value.SetFloat on int Value
//valueS.Index(1).SetFloat(100)
}
代码输出如下
$ go run main.go
valueS Kind:slice CanSet:false Index(0).CanSet:true
after edit:[10 20 3]
如果需要整体修改修改slice,那么需要传入slice的地址
func main() {
s := []int{1, 2, 3}
// slice的指针
valuePtrS := reflect.ValueOf(&s)
fmt.Printf("valuePtrS kind:%v CanSet:%v\n", valuePtrS.Kind(), valuePtrS.CanSet())
// 获取指针指向的内容
valueS := valuePtrS.Elem()
fmt.Printf("valueS kind:%v CanSet:%v\n", valueS.Kind(), valueS.CanSet())
// 整体修改slice
valueS.Set(reflect.ValueOf([]int{4, 5, 6, 7}))
fmt.Printf("replace edit:%v\n", s)
}
代码输出如下
$ go run main.go
valuePtrS kind:ptr CanSet:false
valueS kind:slice CanSet:true
replace edit:[4 5 6 7]
4. 修改array
array不是引用类型,因此func ValueOf(i any) Value需要传入array的地址。
func main() {
s := [3]int{1, 2, 3}
// array的指针
valuePtrS := reflect.ValueOf(&s)
fmt.Printf("valuePtrS kind:%v CanSet:%v\n", valuePtrS.Kind(), valuePtrS.CanSet())
// 获取指针指向的内容
valueS := valuePtrS.Elem()
fmt.Printf("valueS kind:%v CanSet:%v\n", valueS.Kind(), valueS.CanSet())
// 修改指定下标数据
valueS.Index(0).SetInt(10)
fmt.Printf("after edit:%v\n", s)
// 整体修改slice
valueS.Set(reflect.ValueOf([3]int{4, 5, 6}))
fmt.Printf("replace edit:%v\n", s)
//panic: reflect.Set: value of type [4]int is not assignable to type [3]int
//valueS.Set(reflect.ValueOf([4]int{4, 5, 6}))
}
代码输出如下
$ go run main.go
valuePtrS kind:ptr CanSet:false
valueS kind:array CanSet:true
after edit:[10 2 3]
replace edit:[4 5 6]
5. 修改结构体
带修改的结构体的成员的字段名首字母需要大写。
func main() {
type myStruct struct {
Num int `json:"num_json" orm:"column:num_orm"`
Desc string `json:"desc_json" orm:"column:desc_orm"`
}
s := myStruct{
Num: 1,
Desc: "desc",
}
valueS := reflect.ValueOf(&s)
// 指针本身不可修改 可指向的内容
fmt.Printf("Kind:%v CanSet:%v\n", valueS.Kind(), valueS.CanSet())
// 获取指针指向的内容
valueS = valueS.Elem()
fmt.Printf("Kind:%v CanSet:%v Field(0).CanSet:%v\n", valueS.Kind(), valueS.CanSet(), valueS.Field(0).CanSet())
// 修改指定成员的值
valueS.Field(0).SetInt(10)
fmt.Printf("after edit:%+v\n", s)
// 替换整体内容
valueS.Set(reflect.ValueOf(myStruct{Num: 100, Desc: "new desc"}))
fmt.Printf("after replace:%+v\n", s)
}
代码输出如下,
$ go run main.go
Kind:ptr CanSet:false
Kind:struct CanSet:true Field(0).CanSet:true
after edit:{Num:10 Desc:desc}
after replace:{Num:100 Desc:new desc}
6. 修改map
反射通过func (v Value) SetMapIndex(key, elem Value)修改map指定key的value
func main() {
m := map[int]string{
1: "1",
2: "2",
3: "3",
}
valueM := reflect.ValueOf(m)
// 迭代器访问
iter := valueM.MapRange()
for iter.Next() {
fmt.Printf("key:%v val:%v\n", iter.Key(), iter.Value())
// 将所有value修改为"a"
valueM.SetMapIndex(iter.Key(), reflect.ValueOf("a"))
}
fmt.Println("--- after edit ---")
// 通过key访问
keys := valueM.MapKeys()
for i := 0; i < len(keys); i++ {
fmt.Printf("key:%v val:%v\n", keys[i], valueM.MapIndex(keys[i]))
}
}
代码输出如下
$ go run main.go
key:1 val:1
key:2 val:2
key:3 val:3
--- after edit ---
key:1 val:a
key:2 val:a
key:3 val:a
Golang反射修改变量值的更多相关文章
- 通过反射将变量值转为变量名本身ZZ
这是.NET反射的一个有趣小例子: 通过反射将变量值转为变量名本身. 当然要先添加命名空间:using System.Reflection; 示例代码如下: class Program { st ...
- IDEA在debug时修改变量值
IDEA在debug调试时修改变量值 例如以下代码: int y1 = 0; anchor.setDy1(y1); 在代码中,这个y1永远是0,但是y1本身是个变量 debug的时候获取到这个属性,并 ...
- sap 调试工具,修改变量值
1: 点击修改,输入变量值,按enter键.
- JS变量写到HTML页面中并修改变量值(前台处理数据序号问题)
有时候我们在前台需要对序号进行处理,我们需要将JS变量写到页面中进行显示. 第一种方式:后台处理 第二种方式:JS中定义全局变量,然后进行显示,可以书写一个JS函数对不同的需要进行不同的替换,也就可以 ...
- Java反射-修改private final成员变量值,你知道多少?
大家都知道使用java反射可以在运行时动态改变对象的行为,甚至是private final的成员变量,但并不是所有情况下,都可以修改成员变量.今天就举几个小例子说明. 基本数据类型 String类型 ...
- Java 反射修改类的常量值、静态变量值、属性值
前言 有的时候,我们需要修改一个变量的值,但变量也许存在于 Jar 包中或其他位置,导致我们不能从代码层面进行修改,于是我们就用到了下面的场景,通过反射来进行修改变量的值. 定义一个实体类 class ...
- 动态修改 NodeJS 程序中的变量值
如果一个 NodeJS 进程正在运行,有办法修改程序中的变量值么?答案是:通过 V8 的 Debugger 接口可以!本文将详细介绍实现步骤. 启动一个 HTTP Server 用简单的 Hello ...
- saltstack通过jinja模板,将变量值增加到配置文件中?通过引用变量值修改配置文件?
需求描述: 在使用saltstack的时候,有的时候,需要根据不同的变量来增加配置,比如,bind,监听端口,这些都可以通过变量写入,并且在配置的时候引用,下面是一个例子,用来演示,如何使用jinja ...
- jetty debug修改 java static 静态变量值不会生效
在jetty debug模式下修改static静态变量值不会重新Load 因为jetty是嵌入式web容器,static静态变量是全局的,如果想生效,就必须重启jetty 在热部署的时候tomcat会 ...
- Java反射之修改常量值
1. 通过反射修改常量的值 package com.blueStarWei.invoke; import java.lang.reflect.Field; public class ModifyFin ...
随机推荐
- Prometheus样本采集器汇总
系统基本信息 Linux Servers: Exporter https://github.com/prometheus/node_exporter Dashboard https://grafana ...
- 推送本地镜像到Dokcer Hub仓库
# 登陆 [root@docker ~]# docker login # 注意:后面不输入网址 Login with your Docker ID to push and pull images fr ...
- .NET 反向代理 YARP 自定义配置提供程序(Configuration Providers)
介绍 基本 Yarp 示例显示从 appsettings.json 加载的代理配置.相反,代理配置可以从您选择的源以编程方式加载.您可以通过提供几个实现 IProxyConfigProvider 和 ...
- 关于vmware虚拟机的ova/ovf转换成aws上的AMI镜像
很多时候,我们会有这样的需求,需要将DC中vmware虚拟化的服务器,迁移到aws上,我们就得先将vmware虚拟机导出,然后转换 关于vmvare虚拟的导出备份,一般有ova(Open Virtua ...
- [Android开发学iOS系列] 快速上手UIKit
快速上手iOS UIKit UIKit是苹果官方的framework, 其中包含了各种UI组件, window和view, 事件处理, 交互, 动画, 资源管理等基础设施支持. 按照前面的介绍, 用U ...
- ssh端口映射 解决服务器使用tensorboard的问题
有时会在服务器上使用tensorboard,然而本地无法直接访问tensorboard结果网页.这时候使用端口映射即可.比如tensorboard上占用的是 6006 端口,也就是说结果在服务器的 l ...
- 图解 | 聊聊 MyBatis 缓存
首发公众号-悟空聊架构:图解 | 聊聊 MyBatis 缓存 你好,我是悟空. 本文主要内容如下: 一.MyBatis 缓存中的常用概念 MyBatis 缓存:它用来优化 SQL 数据库查询的,但是可 ...
- 已知数据库中存在表tb_book2,通过在图书信息界面填写书本的基本信息,然后提交后写入数据库中的表格中。需要对提交的信息进行修改,信息填入不能为空,为空则则有提示。
jsp结合SQLSERVER向数据库中的表添加图书信息. 已知数据库中存在表tb_book2,通过在图书信息界面填写书本的基本信息,然后提交后写入数据库中的表格中.需要对提交的信息进行修改,信息填入不 ...
- 前端框架Vue------>第一天学习(3)
文章目录 8 .使用Axios实现异步通信 9 .表单输入绑定 9.1 . 什么是双向数据绑定 9.2 .为什么要实现数据的双向绑定 9.3 .在表单中使用双向数据绑定 8 .使用Axios实现异步通 ...
- [WPF] 抄抄超强的苹果官网滚动文字特效实现
1. 前言 今天 ChokCoco 大佬发布了一篇博客 超强的苹果官网滚动文字特效实现,iPhone 我是买不起的,但不妨碍我对抄特效感兴趣,正好我这周安排的工作已经完成了,于是有空练练手实现了一个 ...