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 ...
随机推荐
- springMVC中Restful支持
RESTFul支持 http://localhost:8090/user/doAdd.action?username=tony&age=8 http://localhost:8090/user ...
- perl学习笔记——文件测试
文件测试主要用于查看如文件是否存在.文件大小.文件更新时间等信息. 文件测试操作符 -e 测试文件是否存在: die "Oops!A file called '$filename' alr ...
- Java8 CompletableFuture组合式的编程(笔记)
* 实现异步API public double getPrice(String product) { return calculatePrice(product); } /** * 同步计算商品价格的 ...
- 基于.NET的轻量级微信SDK
一.前言 特别不喜欢麻烦的一个人,最近碰到了微信开发.下载下来了一些其他人写的微信开发“框架”,但是被恶心到了,实现的太臃肿啦. 最不喜欢的就是把微信返回的xml消息在组装成实体类,所以会比较臃肿,现 ...
- 怎样用Google APIs和Google的应用系统进行集成(4)----获得Access Token以通过一些Google APIs的OAuth2认证
在上篇文章中: "怎样用Google APIs和Google的应用系统进行集成(3)----调用发现Google APIs的RESTful的服务"一文中,我们直接用jdk的java ...
- 【高德地图API】从零開始学高德JS API(二)地图控件与插件——測距、圆形编辑器、鼠标工具、地图类型切换、鹰眼鱼骨
不管是控件还是插件,都是在一级API接口的基础上,进行二次开发,封装的一系列更加便于开发人员使用.降低开发人员工作量的二级API接口.除了官方通用的鱼骨.鹰眼控件,还有大量官方开发的地图插件,相似谷歌 ...
- Gperftools中tcmalloc的简介和使用(转)
TcMalloc(Thread-CachingMalloc)是google-perftools工具中的一个内存管理库,与标准的glibc库中malloc相比,TcMalloc在内存分配的效率和速度上要 ...
- Linq的日期比较
在一个项目中要进行linq的日期比较,从一个表的时间类型字段中取出日期,比较是否为当天日期.语句如下: epark_middlelayerEntities eparkMiddle = new epar ...
- JAVA的IO流:打印流
打印流: 打印流是输出信息最方便的类,注意包含字节打印流PrintStream和字符打印流:PrintWriter.打印流提供了非常方便的打印功能, 可以打印任何类型的数据信息,例如:小数,整数,字符 ...
- centos mysql iptables配置
在CentOS系统中防火墙默认是阻止3306端口的,我们要是想访问mysql数据库,我们需要这个端口,命令如下: iptables -I INPUT -p tcp --dport 3036 -j AC ...