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. 设计模式 之 原型模式(ProtoType)

    什么时原型模式   或   原型模式的定义: 用原型实例来指定创建对象的种类,并通过拷贝这些原型创建新的对象. 原型模式的特点: 1),它是面向接口编程, 2),原型模式的新对象是对原型实例的一个克隆 ...

  2. form表单提交问题

    1.提交后不能跳转到指定页面 jsp代码 <form class="form-horizontal" role="form"> <p clas ...

  3. 安卓四核PDA手持PDA智能POS机 打印二维码 分享

    很多项目都会用到 类似的要求  移动手持终端 通过程序 可以生成条码或二维码 打印出小票或标签纸 下面直接上代码 希望对大家有点用处 private void print(){ csys.setTex ...

  4. 控制Storyboard播放zz

    <Grid Width="300" Height="460"> <Grid.RowDefinitions> <RowDefinit ...

  5. Codeforces Round #344 (Div. 2) B. Print Check

    B. Print Check time limit per test 1 second memory limit per test 256 megabytes input standard input ...

  6. JavaScript使用封装

    基本封装方法 请看下面的例子: var Person = function(name,age){ this.name = name; this.age = age || "未填写" ...

  7. Liquid Exception: Included file '_includes/customizer-variables.html' not found in assets/bootstrap/docs/customize.html 解决方案

    执行下面这句话即可 rm -rf source/assets/bootstrap/docs/

  8. tessnet2.Tesseract Init程序退出问题解决

    1.检查语言包与引用库版本是否一致.2.0需要使用2.0的语言包.(http://www.pixel-technology.com/freeware/tessnet2/) 2.是否安装过3.0,安装中 ...

  9. [RxJava^Android]项目经验分享 --- 异常方法处理

    简单介绍一下背景,最近RxJava很火,我也看来学习一下,计划在项目的独立模块中使用它.使用过程中遇到很多问题,在这里记录分享一下.可能有使用不当的地方,大家多多包涵.对于RxJava的基本概念和功能 ...

  10. BZOJ4455: [Zjoi2016]小星星

    Description 小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有n颗小星星,用m条彩色的细线串了起来,每条细 线连着两颗小星星.有一天她发现,她的饰品被破坏了,很多细线都被拆掉了.这 ...