go reflect 取指针_Go之如何操作结构体的非导出字段
Dig101: dig more, simplified more and know more
我们都知道Go
的struct
里,小写字段是非导出的,即不可从包外部访问。
但非导出字段在外部也并不是没有办法访问,也不是不可以修改。
今天看下reflect
包如何在包外操作非导出字段。
文章目录
取地址访问
取地址修改
非取地址访问
非取地址修改
取地址访问
先来看第一个函数NewAt
:
对于结构体,通过其底层地址(指针 p)和类型,返回指向该结构体的一个指针,
该值是可寻址的(addressable
),即可访问该结构体
// reflect/value.go// NewAt returns a Value representing a pointer to a value of the// specified type, using p as that pointer.func NewAt(typ Type, p unsafe.Pointer) Value { fl := flag(Ptr) t := typ.(*rtype) return Value{t.ptrTo(), p, fl}}
有个这个方法,就可以通过struct
的反射获取非导出字段
比如访问,对于如下含有非导出字段的结构体Example
package testDatatype Example struct { a string}
便可以通过对结构体eg
取地址的方式,获取其非导出字段a
的内容
这里Elem
是获取其底层数据对象的方式,
如果知道类型,也可显示指定调用,如reflect.value.Interface, reflect.value.Int...
var eg testData.Examplea:=GetStructPtrUnExportedField(&eg, "a").String()
func GetStructPtrUnExportedField(source interface{}, fieldName string) reflect.Value { // 获取非导出字段反射对象 v := reflect.ValueOf(source).Elem().FieldByName(fieldName) // 构建指向该字段的可寻址(addressable)反射对象 return reflect.NewAt(v.Type(), unsafe.Pointer(v.UnsafeAddr())).Elem()}
这里注意必须要对eg
取地址, 否则会panic
:
panic: reflect: call of reflect.Value.Elem on struct Value
因为reflect.Value.Elem
需要reflect.Value
类型必须是interface
或者ptr
,
这样获取其底层的值才有意义:要么返回interface
底层的值或者ptr
指向的值
其注释如下:
// Elem returns the value that the interface v contains// or that the pointer v points to.// It panics if v's Kind is not Interface or Ptr.// It returns the zero Value if v is nil.func (v Value) Elem() Value {
取地址修改
那可以访问了,如何修改呢?
利用reflect.value.Set
就可以:
上边Elem
获取到的反射值是可修改的(assignable
),突破了非导出字段不能从外部修改的限制
var eg testData.Exampleerr := SetStructPtrUnExportedStrField(&eg, "a", "test")
func SetStructPtrUnExportedStrField(source interface{}, fieldName string, fieldVal interface{}) (err error) { v := GetStructPtrUnExportedField(source, fieldName) rv := reflect.ValueOf(fieldVal) if v.Kind() != rv.Kind() { return fmt.Errorf("invalid kind: expected kind %v, got kind: %v", v.Kind(), rv.Kind()) } // 修改非导出字段值 v.Set(rv) return nil}
这里是以反射值来修改非导出字段值,内部类型须一致。修改后内容会直接反应到eg
上
类似的还有指定类型的设置方法如SetString,SetBool...
非取地址访问
当然不取地址也是可以访问非导出字段的。
这里用到的第二个函数是New
:
基于指定类型创建一个可以表示该类型的指针
// New returns a Value representing a pointer to a new zero value// for the specified type. That is, the returned Value's Type is PtrTo(typ).func New(typ Type) Value { if typ == nil { panic("reflect: New(nil)") } t := typ.(*rtype) ptr := unsafe_New(t) fl := flag(Ptr) return Value{t.ptrTo(), ptr, fl}}
具体访问代码如下:
func GetStructUnExportedField(source interface{}, fieldName string) (accessableField, addressableSourceCopy reflect.Value) { v := reflect.ValueOf(source) // since source is not a ptr, get an addressable copy of source to modify it later addressableSourceCopy = reflect.New(v.Type()).Elem() // make a copy of source addressableSourceCopy.Set(v) accessableField = addressableSourceCopy.FieldByName(fieldName) accessableField = reflect.NewAt(accessableField.Type(), unsafe.Pointer(accessableField.UnsafeAddr())).Elem() return}
这样其实是内部构造了一个对该结构取地址的指针,以满足后续调用Elem
时可寻址!
非取地址修改
非取地址的方式访问没有问题,要还想修改就不会反应到原始结构体上了
毕竟是内部重新拷贝了一个结构体进行的操作。
具体操作类似取地址修改的方式,这里不赘述了。
实际使用中,还是通过NewAt
获取可读写的非导出字段更方便一些。
本文代码见 NewbMiao/Dig101-Go
推荐阅读
Dig101-Go之如何在函数内修改指针
如果有用,点个 在看,让更多人看到
外链不能跳转,戳
go reflect 取指针_Go之如何操作结构体的非导出字段相关推荐
- go reflect 取指针_Go的方法集详解
女主宣言 Go语言以其本身具有的高并发特性,在云计算开发中,得到了广泛的应用,也深受广大开发者的欢迎.但是大家对go语言真的了解了么?本文作者经过对go语言的多年实践应用,现对go语言中的方法集进行了 ...
- 利用返回引用来操作结构体
1 #include "stdafx.h" 2 #include <iostream.h> 3 #include <string.h> 4 5 /***** ...
- C语言:指针的偏移步长、结构体成员的偏移量、嵌套结构体成员的偏移量、结构体的内存对齐
文章目录 1 不同类型指针的偏移步长 2 结构体成员的偏移量 3 嵌套结构体成员的偏移量 4 结构体的内存对齐 4.1 内存对齐的原因与优点 4.2 结构体内存对齐的规则 4.3 结构体嵌套结构体时的 ...
- 用结构体指针指向(-)或结构体变量加点(.)后不出现结构体成员
今天写代码时遇到这么个问题:用结构体指针指向(->)或结构体变量加点(.)后不出现结构体成员,虽然不影响编写,但效率降低,容易出错. 代码入下: stack.h #ifndef __STACK_ ...
- 【C 语言】结构体 ( 指针运算与指针内存操作 | 结构体成员偏移量计算 )
文章目录 一.指针运算 与 指针内存操作 二.结构体偏移量计算 一.指针运算 与 指针内存操作 指针变量算术运算 ( 指针可以是任意值 ) : 指针 是一个变量 , 如果对指针进行 算术 / 逻辑 等 ...
- C语言—用结构体指针给数组赋值(结构体指针指向字符串,给字符串赋值)
数组定义: char acBuf[sizeof(TRANS_HEAD_S) + sizeof(USER_HEAD_S) + 4] = {0}; 结构体定义: typedef struct {int i ...
- c语言中指针数组赋值字符串,C语言—用结构体指针给数组赋值(结构体指针指向字符串,给字符串赋值)...
数组定义: char acBuf[sizeof(TRANS_HEAD_S) + sizeof(USER_HEAD_S) + 4] = {0}; 结构体定义: typedef struct { int ...
- go结构体初始化_go语言基础之结构体普通变量初始化
1.结构体 1.1.结构体类型 有时我们需要将不同类型的数据组合成一个有机的整体,如:一个学生有学号/姓名/性别/年龄/地址等属性.显然单独定义以上变量比较繁琐,数据不便于管理. 结构体是一种聚合的数 ...
- c语言中定义结构体指针的作用,C语言结构体定义,使用及指针(1)
前言 C语言中的结构体作为一大难点,并且对于需要学习数据结构的同学来说,这个结构是每次上课都会遇到的,所以,我们只有更深层次的理解结构体的知识,才能更好的掌握数据结构 结构体用处 结构体到底有什么用? ...
最新文章
- oracle 分区使用情况,Oracle Hash分区的使用总结
- AAAI | 深度生成模型—NEVAE
- pointnet 结果可视化_PointNet论文复现及代码详解
- Linux Kernel TCP/IP Stack — 协议栈发包处理流程
- 第四十六期:关于云存储的五大优势
- 数字农业WMS库存操作重构及思考
- 新年UI的拆红包源码/5级代理功能/会员中心充值接口完善
- CleanCodeHandbook Chapter 6: Misc(35-38)
- 中国晶体谐振器行业市场供需与战略研究报告
- 还不知道事务消息吗?这篇文章带你全面扫盲!
- PEST分析顺丰服务需求_这个工作值不值得去做?4种分析模型及3种曲线让你学会观察行业...
- FPGA原型验证、硬件加速器(emulater 模拟器)、和aws FPGA公有云区别
- Ubuntu20.04 Clion/Pycharm/IDEA 输入中文+光标跟随解决方案
- SCU 4487 king's trouble I
- C#保存图片、压缩图片大小、缩放图片比例
- 妮可妮可妮 [Hash]
- 【软件工程】绘制状态转换图
- 穷养儿,富养女一一原来是指这样
- HCIP课程笔记-06-DR/BDR、OSPF各网络环境下的工作方式、OSPF的hello包、DBD包、LSR包、LSU包、LSAck;
- 北邮智能车仿真培训(九)—— 室外光电创意组仿真