声明:文章内容取自雨痕老师《Go语言学习笔记》

和Type获取类型信息不同,Value专注于对象实例数据读写。

在前面章节曾提到过,接口变量会复制对象,且是unaddressable的,所以要想修改目标对象,就必须使用指针。

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. func main() {
  7. a := 100
  8. va, vp := reflect.ValueOf(a), reflect.ValueOf(&a).Elem()
  9. fmt.Println(va.CanAddr(), va.CanSet())
  10. fmt.Println(vp.CanAddr(), vp.CanSet())
  11. }

输出:

  1. false false
  2. 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)

}

  1. 输出:

name:canaddr = true,canset = true

code:canaddr = true,canset = false

{Name:Tom code:100}

  1. <hr>
  2. Value.Pointer和Value.Int等方法类似,将Value.data存储的数据转换为指针,目标必须是指针类型。而UnsafeAddr返回任何CanAddr Value.data地址(相当于&取地址操作),比如Elem后的Value,以及字段成员地址。
  3. 以结构体里的指针类型字段为例,Pointer返回该字段所保存的地址,而UnsafeAddr返回该字段自身的地址(结构对象地址+偏移量)
  4. <hr>
  5. 可通过Interface方法进行类型推断和转换。
  6. ```golang
  7. package main
  8. import (
  9. "fmt"
  10. "reflect"
  11. )
  12. type user struct {
  13. Name string
  14. Age int
  15. }
  16. func main() {
  17. u := user{
  18. "雨痕",
  19. 60, //如果最后一个字段不和}相连,则必须加上,
  20. }
  21. v := reflect.ValueOf(&u)
  22. if !v.CanInterface() {
  23. fmt.Println("CanInterfae:fail.")
  24. return
  25. }
  26. p, ok := v.Interface().(*user)
  27. if !ok {
  28. fmt.Println("Interface:fail.")
  29. return
  30. }
  31. p.Age++
  32. fmt.Printf("%+v\n", u)
  33. }

输出:

  1. {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())

}

}

  1. 输出:

100 true

  1. 接口有两种nil状态,这一直是个潜在麻烦。解决方法是用IsNil判断值是否为nil
  2. ```golang
  3. package main
  4. import (
  5. "fmt"
  6. "reflect"
  7. )
  8. func main() {
  9. var a interface{} = nil
  10. var b interface{} = (*int)(nil)
  11. fmt.Println(a == nil)
  12. fmt.Println(b == nil, reflect.ValueOf(b).IsNil())
  13. }

输出:

  1. true
  2. false true

也可用unsafe转换后直接判断iface.data是否为零值。

  1. package main
  2. import (
  3. "fmt"
  4. "unsafe"
  5. )
  6. func main() {
  7. var b interface{} = (*int)(nil)
  8. iface := (*[2]uintptr)(unsafe.Pointer(&b))
  9. fmt.Println(iface, iface[1] == 0)
  10. }

输出:

  1. &[4785664 0] true

让人很无奈的是,Value里的某些方法并未实现ok-idom或返回error,所以得自行判断返回的是否为Zero Value。

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. func main() {
  7. v := reflect.ValueOf(struct{ name string }{})
  8. fmt.Println(v.FieldByName("name").IsValid())
  9. fmt.Println(v.FieldByName("xxx").IsValid())
  10. }

输出:

  1. true
  2. 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. flume分布式日志收集系统操作

    1.flume是分布式的日志收集系统,把收集来的数据传送到目的地去. 2.flume里面有个核心概念,叫做agent.agent是一个java进程,运行在日志收集节点. 3.agent里面包含3个核心 ...

  2. Android基础新手教程——4.1.2 Activity初窥门径

    Android基础新手教程--4.1.2 Activity初窥门径 标签(空格分隔): Android基础新手教程 本节引言: 上一节中我们对Activity一些主要的概念进行了了解,什么是Activ ...

  3. HTTP——请求和响应格式

    HTTP请求格式:<request-line><headers><blank line>[<request-body>]说明:第一行必须是一个请求行(r ...

  4. 微信小程序 如何定义全局函数?

    微信小程序 定义全局数据.函数复用.模版等 微信小程序定义全局数据.函数复用.模版等问题总结: 1.如何定义全局数据 在app.js的App({})中定义的数据或函数都是全局的,在页面中可以通过var ...

  5. javascript获取日期的年,月,日

    var date = new Date(strTime); return date.getFullYear()+"-"+(date.getMonth()+1)+"-&qu ...

  6. struts上传文件 血案

    记录一个图片上传之后没有后缀 拓展名问题 平常我们查询数据都是  fileImage=fileImageService.getQuery();  让entity等于它 那么fileImage.getF ...

  7. ADO.NET基础知识学习(SQLCOnnection&SQLCommand&SQLDataReader&SQLDataAdapter&DataSet)

    通过ADO.NET技术,我们可以高效的完成客户端同数据库之间的数据访问操作,便于我们在客户端程序简便高效的访问以及获取数据库中的有用数据,同时也可以对数据库中的数据进行更新,即可以完成客户端与数据库之 ...

  8. AngularJs学习笔记(2)——ng-include

    编写html文档的时候,为了实现代码模块化,增加复杂页面的代码可读性和可维护性,我们常常会想到将代码分散写入不同的HTML文件 angularJS里面的ng-include指令结合ng-control ...

  9. kafka快速开始教程

    此教程假设你刚刚开始没有任何 Kafka 或 ZooKeeper 数据.Kafka的控制台脚本在类Unix和Windows平台不同,Windows平台使用bin\windows\\代替bin/,脚本的 ...

  10. .htaccess中的apache rewrite规则写法详解(未完)

    转:http://www.cnblogs.com/adforce/archive/2012/11/23/2784664.html http://blog.csdn.net/Long_Xiao_Yun/ ...