go语言中reflect反射机制。详细原文:地址

接口值到反射对象

package mainimport ("fmt""reflect"
)func main() {var x int = 1fmt.Println("type: ", reflect.TypeOf(x))
}

type:  int

TypeOf函数的定义如下,参数为接口类型,返回值为类型

func TypeOf(i interface {}) Type

ValueOf函数的定义如下,参数为接口类型,返回值为Value

var x int = 1
fmt.Println("value: ", reflect.ValueOf(x))
value:  <int Value>

可以通过Kind函数来检查类型,

fmt.Println("Kind:  ", reflect.ValueOf(x).Kind())
fmt.Println("Kind is Int? ", reflect.ValueOf(x).Kind() == reflect.int)

Kind:   int
Kind is Int?  true

反射对象到接口值

通过Interface函数可以实现反射对象到接口值的转换,

func (v Value) Interface() interface {}

// Interface 以 interface{} 返回 v 的值
y := v.Interface().(float64)
fmt.Println(y)

修改反射对象

修改反射对象的前提条件是其值必须是可设置的

var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.3) // Error: panic

为了避免这个问题,需要使用CanSet函数来检查该值的设置性,

var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("settability of v: ", v.CanSet())
settability of v: false

那么如何才能设置该值呢?
这里需要考虑一个常见的问题,参数传递,传值还是传引用或地址?
在上面的例子中,我们使用的是reflect.ValueOf(x),这是一个值传递,传递的是x的值的一个副本,不是x本身,因此更新副本中的值是不允许的。如果使用reflect.ValueOf(&x)来替换刚才的值传递,就可以实现值的修改。


var x float64 = 3.4
p := reflect.ValueOf(&x) // 获取x的地址
fmt.Println("settability of p: ", p.CanSet())
v := p.Elem()
fmt.Println("settability of v: ", v.CanSet())
v.SetFloat(7.1)
fmt.Println(v.Interface())
fmt.Println(x)
settability of p: false
settability of v: true
7.1
7.1

获取结构体标签

首先介绍如何遍历结构体字段内容,
假设结构体如下,

type T struct {A intB string
}t := T{12, "skidoo"}

从而,通过反射来遍历所有的字段内容

s := reflect.ValueOf(&t).Elem()
typeOfT := s.Type()
for i := 0; i < s.NumField(); i++ {f := s.Field(i)fmt.Printf("%d %s %s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface())
}

0 A int = 23
1 B string = skidoo

接下来,如何获取结构体的标签内容?

func main() {type S struct {F string `species:"gopher" color:"blue"`}s := S{}st := reflect.TypeOf(s)field := st.Field(0)fmt.Println(field.Tag.Get("color"), field.Tag.Get("species"))
}

interface{}到函数反射

一般情况下,为了存储多个函数值,一般采用map来存储。其中key为函数名称,而value为相应的处理函数。
在这里需要定义好函数类型,但是函数的参数以及返回类型就需要是统一的,如下

package mainimport "fmt"func say(text string) {fmt.Println(text)
}func main() {var funcMap = make(map[string]func(string))funcMap["say"] = sayfuncMap["say"]("hello")
}

如果希望map可以存储任意类型的函数(参数不同,返回值不同),那么就需要用interface{}而不是func(param...)来定义value。

package mainimport "fmt"func say(text string) {fmt.Println(text)
}func main() {var funcMap = make(map[string]interface{})funcMap["say"] = sayfuncMap["say"]("hello")
}
cannot call non-function funcMap["say"] (type interface {})

直接调用会报错,提示不能调用interface{}类型的函数。

这时,需要利用reflect把函数从interface转换到函数来使用,

package mainimport ("fmt""reflect"
)func say(text string) {fmt.Println(text)
}func Call(m map[string]interface{}, name string, params ... interface{}) (result []reflect.Value) {f := reflect.ValueOf(m[name])in := make([]reflect.Value, len(params))for k, param := range params {in[k] = reflect.ValueOf(param)}result = f.Call(in)return
}func main() {var funcMap = make(map[string]interface{})funcMap["say"] = sayCall(funcMap, "say", "hello")

本文转自cococo点点博客园博客,原文链接:http://www.cnblogs.com/coder2012/p/4881854.html,如需转载请自行联系原作者

golang reflect相关推荐

  1. golang reflect Pointer 获取 传入的interface信息

    使用反射可以获取到数据的类型信息,reflect.TypeOf()返回的数据类型如下: type rtype struct {size uintptrptrdata uintptr // number ...

  2. golang reflect 反射 简介

    和Java语言一样,Go也实现运行时反射,这为我们提供一种可以在运行时操作任意类型对象的能力.比如我们可以查看一个接口变量的具体类型,看看一个结构体有多少字段,如何修改某个字段的值等等. TypeOf ...

  3. golang Reflect包

    2019独角兽企业重金招聘Python工程师标准>>> Reflect包 Reflect 反射包有2个重要的类型,分别通过Typeof()和ValueOf()返回. 分别在源码包里的 ...

  4. golang reflect

    reflect包实现了运行时反射,允许程序操作任意类型的对象.典型用法是用静态类型interface{}保存一个值,通过调用TypeOf获取其动态类型信息,该函数返回一个Type类型值.调用Value ...

  5. Golang的反射reflect深入理解和示例

    [TOC] Golang的反射reflect深入理解和示例 [记录于2018年2月] 编程语言中反射的概念 在计算机科学领域,反射是指一类应用,它们能够自描述和自控制.也就是说,这类应用通过采用某种机 ...

  6. Go 语言编程 — reflect 反射机制

    目录 文章目录 目录 为什么需要反射? reflect 包 通过 reflect.TypeOf() 获取对象的反射类型 reflect.Type 通过 reflect.Elem() 获取指针所指向的对 ...

  7. golang 函数指针相等比较

    使用反射 reflect.ValueOf(functionName).Pointer()  反射详细参考:<golang reflect 反射 简介>https://blog.csdn.n ...

  8. Golang 任意类型切片的增删改查

    文章目录 1.增加元素 1.1 使用 []interface{} 实现 1.2 使用 interface{} 实现 1.3 使用 interface{} 的优雅实现 2.删除元素 3.修改元素 4.查 ...

  9. 年终盘点!2017年超有价值的Golang文章

    由于微信链接没办法直接点击,所以后面这些链接都是需要大家自己copy打开 马上就要进入2018年了,作为年终的盘点,本文列出了一些2017年的关于Go编程的一些文章,并加上简短的介绍. 文章排名部分先 ...

最新文章

  1. Linux 查看端口占用情况 并 结束进程
  2. opencv轻松入门面向python下载_OpenCV轻松入门:面向Python
  3. 如何从几何角度上理解方程组只有一个解_深度科普---电磁波(三):无激励下的真空中的Maxwell方程组的解...
  4. 个人编程思想理解的片段(主要是面向对象的,参考了许多人的观点,还不成熟,没形成系统,请大家多指点)...
  5. java实现qq抢红包_Java实现抢红包功用
  6. mysql 实例启动利用binlog恢复_mysql利用binlog进行数据恢复
  7. linux免密登录(ssh命令)
  8. Java NIO学习篇之PosixFilePermission详解
  9. C++ primer第一章练习笔记及书店程序
  10. javascript 计算后 无聊的小数点处理
  11. sidirect 连接西门子_Intouch 与 CP343-1 通讯设置
  12. linux 调节风扇速度命令,ubuntu系统调节GPU风扇转速
  13. 一键查询全部单号物流是否签收
  14. 力扣第39题dfsdfs(respathtarget-candidates[1]i)#调用递归,组成目标的 i 可以重复用,不用i+1,def dfsdfs(resres,pathtarget,ind
  15. JS web localStorage传值 coolie传值
  16. POJ - 3376 Finding Palindromes(拓展kmp+trie)
  17. Docker、CentOS 8遭弃用,GPT-3、M1芯片撼动技术圈,盘点2020影响开发者的十大事件!...
  18. 安卓修改电池容量教程_手机电池校正 - 安卓最精确的电量校正方法 - iTeknical
  19. 语音识别-关键词检测
  20. 滑稽,使用paddle轻松搞定抠图,妈妈再也不用担心我不会抠图了

热门文章

  1. windows10 mysql 5.5.36 安装
  2. pyinstaller打包venv(虚拟环境),.pyd文件,非.py文件打包
  3. 三十一、二叉排序树的创建、删除和遍历
  4. CNN阴影去除--DeshadowNet: A Multi-context Embedding Deep Network for Shadow Removal
  5. 查询服务器上几张显卡命令
  6. springboot自定义jar通过enable配置是否开启
  7. Java线程池中submit()和execute()方法有什么区别
  8. C++__conversion function,Non-explicit one argument constructor
  9. java 分析jstack日志_望闻问切使用jstack和jmap剖析java进程各种疑难杂症
  10. RabbitMQ(三):RabbitMQ 使用场景