博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
golang reflect
阅读量:6786 次
发布时间:2019-06-26

本文共 3093 字,大约阅读时间需要 10 分钟。

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

接口值到反射对象

package mainimport (    "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 = 1fmt.Println("value: ", reflect.ValueOf(x))
value:  

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

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

反射对象到接口值

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

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

修改反射对象

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

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

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

var x float64 = 3.4v := 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.4p := 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: falsesettability of v: true7.17.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 = 231 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"] = say    funcMap["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"] = say    funcMap["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"] = say    Call(funcMap, "say", "hello")

本文 由  创作,采用 进行许可。欢迎转载,请注明出处:
转载自: 

你可能感兴趣的文章
centos7安装docker镜像源管理工具harbor
查看>>
vim工具的编辑模式及命令模式
查看>>
DevExpress v17.2新版亮点——Data Access
查看>>
Java Script 第七节课 Java Script的逻辑运算符的例子
查看>>
CSS 3 伪类选择器
查看>>
swfit学习函数
查看>>
UML状态机
查看>>
Java过滤器,SpringMVC拦截器之间的一顺序点关系
查看>>
决心书
查看>>
linux系统管理之存储管理
查看>>
组播RPF 逆向路径转发 实验原理
查看>>
Centos 定时重启 Tomcat
查看>>
java i++
查看>>
linux运维基础篇 unit10
查看>>
linux运维基础篇 unit12
查看>>
俯身倾耳以请
查看>>
程序猿们_你是从头学起_还是半路出家的
查看>>
关于缓存的基础概念
查看>>
智能合约语言 Solidity 教程系列8 - Solidity API
查看>>
机器学习、深度学习、和AI算法可以在网络安全中做什么?
查看>>