golang reflect

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

接口值到反射对象

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. func main() {
  7. var x int = 1
  8. fmt.Println("type: ", reflect.TypeOf(x))
  9. }
  1. type: int

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

  1. func TypeOf(i interface {}) Type

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

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

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

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

反射对象到接口值

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

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

修改反射对象

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

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

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

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

那么如何才能设置该值呢?

这里需要考虑一个常见的问题,参数传递,传值还是传引用或地址?

在上面的例子中,我们使用的是reflect.ValueOf(x),这是一个值传递,传递的是x的值的一个副本,不是x本身,因此更新副本中的值是不允许的。如果使用 reflect.ValueOf(&x)来替换刚才的值传递,就可以实现值的修改。


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

获取结构体标签

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

假设结构体如下,

  1. type T struct {
  2. A int
  3. B string
  4. }
  5. t := T{12, "skidoo"}

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

  1. s := reflect.ValueOf(&t).Elem()
  2. typeOfT := s.Type()
  3. for i := 0; i < s.NumField(); i++ {
  4. f := s.Field(i)
  5. fmt.Printf("%d %s %s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface())
  6. }
  1. 0 A int = 23
  2. 1 B string = skidoo

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

  1. func main() {
  2. type S struct {
  3. F string `species:"gopher" color:"blue"`
  4. }
  5. s := S{}
  6. st := reflect.TypeOf(s)
  7. field := st.Field(0)
  8. fmt.Println(field.Tag.Get("color"), field.Tag.Get("species"))
  9. }

interface{}到函数反射

一般情况下,为了存储多个函数值,一般采用map来存储。其中key为函数名称,而value为相应的处理函数。

在这里需要定义好函数类型,但是函数的参数以及返回类型就需要是统一的,如下

  1. package main
  2. import "fmt"
  3. func say(text string) {
  4. fmt.Println(text)
  5. }
  6. func main() {
  7. var funcMap = make(map[string]func(string))
  8. funcMap["say"] = say
  9. funcMap["say"]("hello")
  10. }

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

  1. package main
  2. import "fmt"
  3. func say(text string) {
  4. fmt.Println(text)
  5. }
  6. func main() {
  7. var funcMap = make(map[string]interface{})
  8. funcMap["say"] = say
  9. funcMap["say"]("hello")
  10. }
  1. cannot call non-function funcMap["say"] (type interface {})

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

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

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. func say(text string) {
  7. fmt.Println(text)
  8. }
  9. func Call(m map[string]interface{}, name string, params ... interface{}) (result []reflect.Value) {
  10. f := reflect.ValueOf(m[name])
  11. in := make([]reflect.Value, len(params))
  12. for k, param := range params {
  13. in[k] = reflect.ValueOf(param)
  14. }
  15. result = f.Call(in)
  16. return
  17. }
  18. func main() {
  19. var funcMap = make(map[string]interface{})
  20. funcMap["say"] = say
  21. Call(funcMap, "say", "hello")

golang reflect的更多相关文章

  1. golang reflect包使用解析

    golang reflect包使用解析 参考 Go反射编码 2个重要的类型 Type Value 其中Type是interface类型,Value是struct类型,意识到这一点很重要 Type和Va ...

  2. golang reflect知识集锦

    目录 反射之结构体tag Types vs Kinds reflect.Type vs reflect.Value 2019/4/20 补充 reflect.Value转原始类型 获取类型底层类型 遍 ...

  3. golang reflect 简单使用举例

    golang中的多态,主要由接口interface体现. 接口interface在实现上,包括两部分:动态类型和动态值. golang提供的reflect包可以用来查看这两部分. 动态类型 func ...

  4. Golang reflect 反射

    反射的规则如下: 从接口值到反射对象的反射  从反射对象到接口值的反射  为了修改反射对象,其值必须可设置   -------------------------------------------- ...

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

    编程语言中反射的概念 在计算机科学领域,反射是指一类应用,它们能够自描述和自控制.也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examin ...

  6. golang中的反射reflect详解

    先重复一遍反射三定律: 1.反射可以将"接口类型变量"转换为"反射类型对象". 2.反射可以将"反射类型对象"转换为"接口类型变量 ...

  7. <转>年终盘点!2017年超有价值的Golang文章

    马上就要进入2018年了,作为年终的盘点,本文列出了一些2017年的关于Go编程的一些文章,并加上简短的介绍. 文章排名不分先后, 文章也不一定完全按照日期来排列.我按照文章的大致内容分了类,便于查找 ...

  8. golang 关于 interface 的学习整理

    Golang-interface(四 反射) go语言学习-reflect反射理解和简单使用 为什么在Go语言中要慎用interface{} golang将interface{}转换为struct g ...

  9. Android Volley获取json格式的数据

    为了让Android能够快速地访问网络和解析通用的数据格式Google专门推出了Volley库,用于Android系统的网络传输.volley库可以方便地获取远程服务器的图片.字符串.json对象和j ...

随机推荐

  1. dos下对mysql的简单操作(linux类似)

    >>>>>>>>>>>>>>>>>>>> 基础入门语句10条 1. 连接服务器  ...

  2. 用div加css做表格去掉外围边框

    通过div做表格时想加上边框,并且想取点外围边框: <div class="cont"> <div class="row"> <a ...

  3. Python爬虫学习(9):Selenium的使用

    1 简介以及安装 Selenium 是什么?一句话,自动化测试工具.它支持各种浏览器,包括 Chrome,Safari,Firefox 等主流界面式浏览器,如果你在这些浏览器里面安装一个 Seleni ...

  4. 通用js地址选择器

    用js实现通用的地址选择器,省份,城市,地区自动关联更新 点击下面查看详细代码: http://runjs.cn/code/s8sqkhcv 关键地址库代码: var addr_arr = new A ...

  5. $(document).ready,$(window).load,window.onload区别和联系

    $(document).ready是在dom结构加载完毕就执行. $(window).load 等价于window.onload,必须等到页面内包括图片的所有元素加载完毕后才能执行. $(docume ...

  6. 【转】《从入门到精通云服务器》第七讲—负载均衡和CDN技术

    在IDC知识中,我们常常会遇上负载均衡与CDN的概念而不知所云.第一讲[什么是云计算], 我们提到过负载均衡,仅给大家留下了印象.这次我们将深入浅出的讲讲到底什么是负载均衡与CDN技术.---互联网数 ...

  7. (RMQ版)LCA注意要点

    inline int lca(int x,int y){ if(x>y) swap(x,y); ]][x]]<h[rmq[log[y-x+]][y-near[y-x+]+]])? rmq[ ...

  8. web应用和虚拟目录映射

    Tip:WEB应用程序 WEB应用程序指供浏览器访问的程序,通常简称为web应用. 一个web应用由多个静态web资源和动态web资源组成,如: HTML.css.js文件 JSP文件.java程序. ...

  9. 根据异常处理对 Java 方法的层次分类

    我根据异常处理对 Java 的方法分为三个层次:1.执行层,2. 处理层,3. 调用层. 执行层方法只抛出异常 throws Exception,是作为代码的基层操作者,可能有多个层次. 处理层方法使 ...

  10. webview使用技巧汇总

    1.webview去除原网址的广告或者标题 js语句 document.documentElement.getElementsByClassName('这里写你要消除的空间的class里面的字符串') ...