golang reflect

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

接口值到反射对象

package main

import (
"fmt"
"reflect"
) func main() {
var x int = 1
fmt.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 int
B 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 main

import "fmt"

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

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

package main

import "fmt"

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

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

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

package main

import (
"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"] = say
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. OpenCv图像裁剪指点区域_roi

    两种方式Range和ROI #include <opencv2/opencv.hpp> using namespace std; using namespace cv; void test ...

  2. 在C#中实现Json的序列化与反序列化

    第一种方式利用 JavaScriptSerializer [对应的Assembly 为 System.Web.Extensions.dll] 进行处理: public static class Kas ...

  3. iOS---FMDB数据升级

    本人在这里重要强调一下!!! 看这里,看这里,看这里,重要的事说三遍. 本人在项目开发中,由于需求问题,不得不对已经建立好的数据库进行修改(添加字段),我就很随意的直接添加了对一个的字段,运行一下,数 ...

  4. Sprint2团队贡献分

    团队贡献分: 郭志豪:31%  http://www.cnblogs.com/gzh13692021053/ 杨子健:22%http://www.cnblogs.com/yzj666/ 谭宇森:23% ...

  5. iOS Real Stuff

    Ray Wenderlich     AppCoda(English)   AppCoda(TW) Awesome iOS      Code4App代码库     CocoaChina代码库   o ...

  6. HDU4787 GRE Words Revenge(AC自动机 分块 合并)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4787 Description Now Coach Pang is preparing for ...

  7. Dictionary Learning(字典学习、稀疏表示以及其他)

    第一部分 字典学习以及稀疏表示的概要 字典学习(Dictionary Learning)和稀疏表示(Sparse Representation)在学术界的正式称谓应该是稀疏字典学习(Sparse Di ...

  8. 如何在Windows上从源码编译Chromium (CEF3) 加入mp3支持

    一.什么是CEF CEF即Chromium Embeded Framework,由谷歌的开源浏览器项目Chromium扩展而来,可方便地嵌入其它程序中以得到浏览器功能. CEF包括CEF1和CEF3两 ...

  9. JSONObject、JSONArray区别

    json,就是一个键对应一个值,超级简单的一对一关系.现在用到的json那可以层层嵌套啊,刚开始接触的时候,确实有种崩溃的赶脚,不想去理,取个数据还那么麻烦.其实,就跟if else语句一样,如果if ...

  10. WINFORM 输出txt文件

    SaveFileDialog saveFile1 = new SaveFileDialog(); saveFile1.Filter = "文本文件(.txt)|*.txt"; sa ...