声明:文章内容取自雨痕老师《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值的更多相关文章

  1. 【记录】【java】反射设值取值

    1.设值 /** * 根据属性名设置属性值 * * @param fieldName * @param object * @return */ public boolean setFieldValue ...

  2. Final修饰的字段是否可以通过反射设置值

    案发现场 经常听说final修饰的字段是常量不能改变的他的值,但是以外发现 Integer.java源码中的字段“value”是final,但是可以通过反射改变他的值. public final cl ...

  3. Go语言反射之值反射

    1 概述 反射不仅可以获取值的类型信息,还可操作变量的值.使用 reflect.Value 类型操作变量的值. 2 值反射对象 reflect.ValueOf() 方法可以获取一个值的反射对象,之后可 ...

  4. 要使用myConfig.properties配置文件作为实体类的映射文件的话,格式要用=,最关键的要和实例类中通过反射获取值的KEY要一样,不样会反射取不到值

    ABC=https://fsdfsdf.iy.comABCId=L2345345ZhP345ABCKey=sfdf4234f234dhE6Ut0aABCName=Gassd010 上面是myConfi ...

  5. 用反射的形式将一个对象属性值赋值给另一个对象,省略点get/set方法的冗余代码

    1.本例使用的是idea 首先需要在idea中安装lombok插件,省略getter和setter方法的书写 在maven项目中加入lombok依赖 <dependency> <gr ...

  6. Go part 7 反射,反射类型对象,反射值对象

    反射 反射是指在程序运行期间对程序本身进行访问和修改的能力,(程序在编译时,变量被转换为内存地址,变量名不会被编译器写入到可执行部分,在运行程序时,程序无法获取自身的信息) 支持反射的语言可以在程序编 ...

  7. 通过JAVA反射,调用未知类的类方法

    下面是一个比较简单的通过JAVA的反射机制调用已知方法的例子 package com.togeek.mvntest; import java.lang.reflect.InvocationTarget ...

  8. struts2 笔记01 登录、常用配置参数、Action访问Servlet API 和设置Action中对象的值、命名空间和乱码处理、Action中包含多个方法如何调用

    Struts2登录 1. 需要注意:Struts2需要运行在JRE1.5及以上版本 2. 在web.xml配置文件中,配置StrutsPrepareAndExecuteFilter或FilterDis ...

  9. 反射获取类中的属性和set属性

    package framework.base; import java.beans.IntrospectionException; import java.beans.PropertyDescript ...

随机推荐

  1. 一起來玩鳥 Starling Framework(2)效能測試以及Image與Texture

    上一篇我們放了一個Quad與TextField在舞台上慢慢轉.眼尖的可能會發現轉起來邊緣有點鋸齒,這可以透過設定Starling的反鋸齒來解決,在Main.as裡,新增了_starling之後,可以加 ...

  2. 基于Spark Mllib,SparkSQL的电影推荐系统

    本文测试的Spark版本是1.3.1 本文将在Spark集群上搭建一个简单的小型的电影推荐系统,以为之后的完整项目做铺垫和知识积累 整个系统的工作流程描述如下: 1.某电影网站拥有可观的电影资源和用户 ...

  3. 通过ssh上传文件到目标主机

    需要通过ssh上传文件到目标主机上,之前一直时通过ssh客户端来传文件的,这次因为本地没装客户端,所以考虑直接用终端通过ssh连接主机进行文件传输. 只需要一条命令就可以了: scp  ./serve ...

  4. 转: 私人珍藏的Chrome插件,吐血推荐

    转:来自 http://stormzhang.com/devtools/2016/01/15/google-chrome-extension/

  5. TestNG+Jenkins+Maven参数化测试dubbo接口

    1.TestNG参数化测试用例: package com.tree.autotest.testcase.IUserBankSummaryService; import com.datatrees.fi ...

  6. 微信小程序 - bindcontroltap和control的关系(map)

    听说最近要废弃control,用cover-image和cover-view替代它,层级问题(我们此等萌新们还在想图标怎么显示在地图上(-.-)) 粗略的来说,一个展示(control),一个触发(b ...

  7. 【Python】self的用法扫盲

    在Python中,我们有两个重要的概念:类与实例 例如:我们在现实生活中人就是一个类,实例就是具体到某一个男人(张三.李四等) 1.类:定义人这个类 class People(object): pas ...

  8. LRU的C++实现引申出的迭代器问题

    leetcode上刷题.碰到一题实现LRU算法的题目. LRU,Least recently used.是一种常见的cache和页面替换算法.算法和原理可以参阅相关wiki. leetcode上的这一 ...

  9. MATLAB读取黑白图像显示却是黑色,24位深转8位深黑白图像解决方法

    1.24位深转8位深: ps将24位深原图.png保存为GIF图256即为8位,再将8位gif图转为需要的.png,即转为8位深png图. 2.MATLAB读取黑白图像显示几乎全为黑色: 这是最近处理 ...

  10. EntityFramework.SqlServer.dll 中发生 其他信息: 在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。未找到或无法访问服务器。请验证实例名称是否正确并且 SQL Server 已配置为允许远程连接。 (provider: Named Pipes Provider, error: 40 - 无法打开到 SQL Server 的连接)

    解决方案: 1.打开Sql server 管理配置器 或者在命令行输入:SQLServerManager10.msc 2.点击MSSQLSERVER的协议,在右侧的页面中选择TCP/IP协议启用 3. ...