设为首页 收藏本站
查看: 1831|回复: 0

[经验分享] golang reflect

[复制链接]

尚未签到

发表于 2018-9-19 11:59:55 | 显示全部楼层 |阅读模式
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:    

  可以通过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(&quot;%d %s %s = %v\n&quot;, 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:&quot;gopher&quot; color:&quot;blue&quot;`
  }
  

  s := S{}
  st := reflect.TypeOf(s)
  field := st.Field(0)
  fmt.Println(field.Tag.Get(&quot;color&quot;), field.Tag.Get(&quot;species&quot;))
  
}
  

interface{}到函数反射
  一般情况下,为了存储多个函数值,一般采用map来存储。其中key为函数名称,而value为相应的处理函数。
  
在这里需要定义好函数类型,但是函数的参数以及返回类型就需要是统一的,如下
  

package main  

  
import &quot;fmt&quot;
  

  
func say(text string) {
  fmt.Println(text)
  
}
  

  
func main() {
  var funcMap = make(map[string]func(string))
  funcMap[&quot;say&quot;] = say
  funcMap[&quot;say&quot;](&quot;hello&quot;)
  
}
  

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

package main  

  
import &quot;fmt&quot;
  

  
func say(text string) {
  fmt.Println(text)
  
}
  

  
func main() {
  var funcMap = make(map[string]interface{})
  funcMap[&quot;say&quot;] = say
  funcMap[&quot;say&quot;](&quot;hello&quot;)
  
}
  

cannot call non-function funcMap[&quot;say&quot;] (type interface {})  

  直接调用会报错,提示不能调用interface{}类型的函数。
  这时,需要利用reflect把函数从interface转换到函数来使用,
  

package main  

  
import (
  &quot;fmt&quot;
  &quot;reflect&quot;
  
)
  

  
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[&quot;say&quot;] = say
  Call(funcMap, &quot;say&quot;, &quot;hello&quot;)
  




运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-594239-1-1.html 上篇帖子: Golang学习 - io 包 下篇帖子: GoLang之协程
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表