go反射----2值
声明:文章内容取自雨痕老师《Go语言学习笔记》
和Type获取类型信息不同,Value专注于对象实例数据读写。
在前面章节曾提到过,接口变量会复制对象,且是unaddressable的,所以要想修改目标对象,就必须使用指针。
package main
import (
"fmt"
"reflect"
)
func main() {
a := 100
va, vp := reflect.ValueOf(a), reflect.ValueOf(&a).Elem()
fmt.Println(va.CanAddr(), va.CanSet())
fmt.Println(vp.CanAddr(), vp.CanSet())
}
输出:
false false
true true
就算传入指针,一样需要通过Elem获取目标对象。因为被接口存储的指针本身是不能寻址和进行设置操作的。
注意,不能对非导出字段直接进行设置操作,无论是当前包还是外包。
```golang
package main
import (
"fmt"
"reflect"
"unsafe"
)
type User struct {
Name string
code int
}
func main() {
p := new(User)
v := reflect.ValueOf(p).Elem()
name := v.FieldByName("Name")
code := v.FieldByName("code")
fmt.Printf("name:canaddr = %v,canset = %v\n", name.CanAddr(), name.CanSet())
fmt.Printf("code:canaddr = %v,canset = %v\n", code.CanAddr(), code.CanSet())
if name.CanSet() {
name.SetString("Tom")
}
if code.CanAddr() {
(int)(unsafe.Pointer(code.UnsafeAddr())) = 100
}
fmt.Printf("%+v\n", *p)
}
输出:
name:canaddr = true,canset = true
code:canaddr = true,canset = false
{Name:Tom code:100}
<hr>
Value.Pointer和Value.Int等方法类似,将Value.data存储的数据转换为指针,目标必须是指针类型。而UnsafeAddr返回任何CanAddr Value.data地址(相当于&取地址操作),比如Elem后的Value,以及字段成员地址。
以结构体里的指针类型字段为例,Pointer返回该字段所保存的地址,而UnsafeAddr返回该字段自身的地址(结构对象地址+偏移量)
<hr>
可通过Interface方法进行类型推断和转换。
```golang
package main
import (
"fmt"
"reflect"
)
type user struct {
Name string
Age int
}
func main() {
u := user{
"雨痕",
60, //如果最后一个字段不和}相连,则必须加上,
}
v := reflect.ValueOf(&u)
if !v.CanInterface() {
fmt.Println("CanInterfae:fail.")
return
}
p, ok := v.Interface().(*user)
if !ok {
fmt.Println("Interface:fail.")
return
}
p.Age++
fmt.Printf("%+v\n", u)
}
输出:
{Name:雨痕 Age:61}
也可直接使用Value.Int、Bool等方法进行类型转换,但失败时会引发panic,且不支持ok-idiom。
复合类型对象设置示例:
```golang
package main
import (
"fmt"
"reflect"
)
func main() {
c := make(chan int, 4)
v := reflect.ValueOf(c)
if v.TrySend(reflect.ValueOf(100)) {
fmt.Println(v.TryRecv())
}
}
输出:
100 true
接口有两种nil状态,这一直是个潜在麻烦。解决方法是用IsNil判断值是否为nil。
```golang
package main
import (
"fmt"
"reflect"
)
func main() {
var a interface{} = nil
var b interface{} = (*int)(nil)
fmt.Println(a == nil)
fmt.Println(b == nil, reflect.ValueOf(b).IsNil())
}
输出:
true
false true
也可用unsafe转换后直接判断iface.data是否为零值。
package main
import (
"fmt"
"unsafe"
)
func main() {
var b interface{} = (*int)(nil)
iface := (*[2]uintptr)(unsafe.Pointer(&b))
fmt.Println(iface, iface[1] == 0)
}
输出:
&[4785664 0] true
让人很无奈的是,Value里的某些方法并未实现ok-idom或返回error,所以得自行判断返回的是否为Zero Value。
package main
import (
"fmt"
"reflect"
)
func main() {
v := reflect.ValueOf(struct{ name string }{})
fmt.Println(v.FieldByName("name").IsValid())
fmt.Println(v.FieldByName("xxx").IsValid())
}
输出:
true
false
go反射----2值的更多相关文章
- 【记录】【java】反射设值取值
1.设值 /** * 根据属性名设置属性值 * * @param fieldName * @param object * @return */ public boolean setFieldValue ...
- Final修饰的字段是否可以通过反射设置值
案发现场 经常听说final修饰的字段是常量不能改变的他的值,但是以外发现 Integer.java源码中的字段“value”是final,但是可以通过反射改变他的值. public final cl ...
- Go语言反射之值反射
1 概述 反射不仅可以获取值的类型信息,还可操作变量的值.使用 reflect.Value 类型操作变量的值. 2 值反射对象 reflect.ValueOf() 方法可以获取一个值的反射对象,之后可 ...
- 要使用myConfig.properties配置文件作为实体类的映射文件的话,格式要用=,最关键的要和实例类中通过反射获取值的KEY要一样,不样会反射取不到值
ABC=https://fsdfsdf.iy.comABCId=L2345345ZhP345ABCKey=sfdf4234f234dhE6Ut0aABCName=Gassd010 上面是myConfi ...
- 用反射的形式将一个对象属性值赋值给另一个对象,省略点get/set方法的冗余代码
1.本例使用的是idea 首先需要在idea中安装lombok插件,省略getter和setter方法的书写 在maven项目中加入lombok依赖 <dependency> <gr ...
- Go part 7 反射,反射类型对象,反射值对象
反射 反射是指在程序运行期间对程序本身进行访问和修改的能力,(程序在编译时,变量被转换为内存地址,变量名不会被编译器写入到可执行部分,在运行程序时,程序无法获取自身的信息) 支持反射的语言可以在程序编 ...
- 通过JAVA反射,调用未知类的类方法
下面是一个比较简单的通过JAVA的反射机制调用已知方法的例子 package com.togeek.mvntest; import java.lang.reflect.InvocationTarget ...
- struts2 笔记01 登录、常用配置参数、Action访问Servlet API 和设置Action中对象的值、命名空间和乱码处理、Action中包含多个方法如何调用
Struts2登录 1. 需要注意:Struts2需要运行在JRE1.5及以上版本 2. 在web.xml配置文件中,配置StrutsPrepareAndExecuteFilter或FilterDis ...
- 反射获取类中的属性和set属性
package framework.base; import java.beans.IntrospectionException; import java.beans.PropertyDescript ...
随机推荐
- flask_admin model官方文档学习
文档地址:http://www.minzhulou.com/docs/flask-admin/api/mod_model.html model在flask_admin算是比较重要的部分,根据文档稍微的 ...
- 纯C实现面向对象之接口编程
创建如下文件目录 : Shape.h #include <stdlib.h> //接口 #ifndef Interface #define Interface struct #endif ...
- shareToQQ,qq 4.1.1 for android,闪退
用shareToQQ函数分享图文消息,在qq 4.1.1 for android版本下打开联系人列表数秒后会闪退!在更高版本的V4.5.2.1,V4.2.1下则没有这个问题(证明各种设置没问题),各位 ...
- Netty4 ServerBootstrap 初始化channelFactory ReflectiveChannelFactory
只需要在启动之前传入你需要用的channel类型就可以了. ServerBootstrap初始化channelFactory过程: 最后我们再来看看这个channelFactory的使用场景:
- Netty 中文教程 (二) Hello World !详解
1.HelloServer 详解 HelloServer首先定义了一个静态终态的变量---服务端绑定端口7878.至于为什么是这个7878端口,纯粹是笔者个人喜好.大家可以按照自己的习惯选择端口.当然 ...
- Java中Vector与ArrayList的差别具体解释
首先看这两类都实现List接口,而List接口一共同拥有三个实现类.各自是ArrayList.Vector和LinkedList.List用于存放多个元素,可以维护元素的次序,而且同意元素的反复. 3 ...
- C++ x86程序与x64程序中,各种内置类型的大小比较
代码: #include <iostream> #include <cstdio> #include <list> #include <string> ...
- 每日一个机器学习算法——k近邻分类
K近邻很简单. 简而言之,对于未知类的样本,按照某种计算距离找出它在训练集中的k个最近邻,如果k个近邻中多数样本属于哪个类别,就将它判决为那一个类别. 由于采用k投票机制,所以能够减小噪声的影响. 由 ...
- MySQL-配置优化技巧
一.连接请求配置 1.查询当前连接数(show full processlist) show full processlist; 2.最大连接数(max_connections) max_connec ...
- windows与虚拟机共享文件夹设置
1.在windows上建立共享文件夹2.virtualbox点击设置-共享文件夹-添加共享文件夹指定windows上的路径,指定名称code: 选择自动挂载.固定分配3.在centos上面执行如下命令 ...