golang reflect
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的更多相关文章
- golang reflect包使用解析
golang reflect包使用解析 参考 Go反射编码 2个重要的类型 Type Value 其中Type是interface类型,Value是struct类型,意识到这一点很重要 Type和Va ...
- golang reflect知识集锦
目录 反射之结构体tag Types vs Kinds reflect.Type vs reflect.Value 2019/4/20 补充 reflect.Value转原始类型 获取类型底层类型 遍 ...
- golang reflect 简单使用举例
golang中的多态,主要由接口interface体现. 接口interface在实现上,包括两部分:动态类型和动态值. golang提供的reflect包可以用来查看这两部分. 动态类型 func ...
- Golang reflect 反射
反射的规则如下: 从接口值到反射对象的反射 从反射对象到接口值的反射 为了修改反射对象,其值必须可设置 -------------------------------------------- ...
- Golang的反射reflect深入理解和示例
编程语言中反射的概念 在计算机科学领域,反射是指一类应用,它们能够自描述和自控制.也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examin ...
- golang中的反射reflect详解
先重复一遍反射三定律: 1.反射可以将"接口类型变量"转换为"反射类型对象". 2.反射可以将"反射类型对象"转换为"接口类型变量 ...
- <转>年终盘点!2017年超有价值的Golang文章
马上就要进入2018年了,作为年终的盘点,本文列出了一些2017年的关于Go编程的一些文章,并加上简短的介绍. 文章排名不分先后, 文章也不一定完全按照日期来排列.我按照文章的大致内容分了类,便于查找 ...
- golang 关于 interface 的学习整理
Golang-interface(四 反射) go语言学习-reflect反射理解和简单使用 为什么在Go语言中要慎用interface{} golang将interface{}转换为struct g ...
- Android Volley获取json格式的数据
为了让Android能够快速地访问网络和解析通用的数据格式Google专门推出了Volley库,用于Android系统的网络传输.volley库可以方便地获取远程服务器的图片.字符串.json对象和j ...
随机推荐
- Nginx+FastCGI运行原理
Nginx不支持对外部程序的直接调用或者解析,所有的外部程序(包括PHP)必须通过FastCGI接口来调用.FastCGI接口在Linux下是socket(这个socket可以是文件socket,也可 ...
- 进击的Python【第十七章】:jQuery的基本应用
进击的Python[第十七章]:jQuery的基本应用
- animation_Frame动画图片轮播
我们刚接触的时候想弄一个轮播图片的一个小案例,但一开始我们以为和以前写java一样,要写一下方法,逻辑:但今天你学了这个Frame动画就可以轻松搞定!下面我们来看看这个Frame是怎么实现的. 第一步 ...
- ubuntu 16.04 + N驱动安装 +CUDA+Qt5 + opencv
Nvidia driver installation(after download XX.run installation file) 1. ctrl+Alt+F1 //go to virtual ...
- HTML5 学习笔记(三)——本地存储
目录 一.HTML4客户端存储 1.1.提交表单发送到服务器的信息 1.2.客户端本地存储概要 二.localStorage 2.1.添加 2.2.取值 2.3.修改 2.4.删除 2.5.跨页面与跨 ...
- IT
http://www.cnblogs.com/TomXu/archive/2011/12/19/2291448.html " 经常从Recruiter那里得到抱怨:“汤姆,为什么面试者每次回 ...
- Hadoop各商业发行版之比较
Hadoop的发行版除了社区的Apache hadoop外,cloudera,hortonworks,mapR,EMC,IBM,INTEL,华为等等都提供了自己的商业版本.商业版主要是提供了专业的技术 ...
- bzoj2743离线+树状数组
奇葩染色,对于每一个点关心的是前前个同颜色的位置,但是处理方法相同 离线比较神奇,按照右端点排序,然后每次用的是左端点,就不用建可持久化树状数组(什么鬼)了 区间修改+单点查询 果断差分以后用树状数组 ...
- PHP用户注册与登录【1】
需求分析 主要功能分为 用户注册.用户登录.用户退出.用户中心 四个部分. 用户注册 用户注册主要功能有: 注册信息表单填写界面 javascript 脚本初步检测用户输入的注册信息. 注册处理模块检 ...
- 移动端常用的meta
1. 禁止缩放:<meta name="viewport" content="width=device-width, initial-scale=1.0, maxi ...