转载

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") 
正文到此结束
Loading...