为了账号安全,请及时绑定邮箱和手机立即绑定

理解golang反射(reflection in Go)

标签:
Go


反射(reflection)是指在运行时,动态获取程序结构信息(元信息)的一种能力,是静态类型语言都支持的一种特性,如Java, golang等。这里主要详细介绍golang reflection相关知识

类型与接口(Types and interfaces)

type MyInt int

var i int

var j MyInt

i 为int类型,j为MyInt类型。虽然i,j底层类型均为int,但它们属于不同类型,没有转换不能相互赋值。

接口类型 interface, 表示一系列方法集合,任意concrete (non-interface) value 只要实现了接口方法,便可赋值给interface

// Reader is the interface that wraps the basic Read method.

type Reader interface {

    Read(p []byte) (n int, err error)

}

// Writer is the interface that wraps the basic Write method.

type Writer interface {

    Write(p []byte) (n int, err error)

}

var r io.Reader

r = os.Stdin

r = bufio.NewReader(r)

r = new(bytes.Buffer)

// and so on

r变量的静态类型为io.Reader,实际类型可能是File, Buffer类型

interface{} 特殊接口类型,没有任何方法,因此任何类型都可赋值给它

The representation of an interface

var r io.Reader

r = new(bytes.Buffer)

r变量的具体类型是io.Reader,实际类型是bytes.Buffer,那么在运行时,golang是如何实现的呢?

一个interface类型的变量存储了2个信息, 一个值,类型对<value,type> pair:

赋给变量的值(concrete value)

变量值的类型描述符(value's type descriptor)

var r io.Reader

tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)

if err != nil {

    return nil, err

}

r = tty

接口类型r 的<value, type> pair是(tty, *os.File)

当然r变量的value tty不仅仅实现了io.Reader接口中的Read方法,还实现了io.Writer中的Write方法,因此可以进行

类型断言(type assertion),试图将r 转换为io.Writer

var w io.Writer

w = r.(io.Writer)

此时,接口变量w的<value,type>pair 为 (tty, *os.File),也就是说r,w 底层value是一样的,可以通过不同的type来暴露不同的方法出来。

继续讨论

var empty interface{}

empty = w //此处不需要type assertion,因为任意类型都可以看作实现了empty interface的方法

接口变量empty的<value,type> pair 为 (tty, *os.File)

Reflection

1. Reflection goes from interface value to reflection object.(接口类型---> 反射类型(reflect.Value,reflect.Type))

反射,可以获取interface类型变量的具体信息(<value,concrete type>)

golang 反射包为reflect

// ValueOf returns a new Value initialized to the concrete value

// stored in the interface i. ValueOf(nil) returns the zero Value.

func ValueOf(i interface{}) Value //获取pair中的value

// TypeOf returns the reflection Type that represents the dynamic type of i.

// If i is a nil interface value, TypeOf returns nil.

func TypeOf(i interface{}) Type   //获取pair中的concrete type

eg:

var r io.Reader

r = os.Stdin   // <value, type> : <os.Stdin, *os.File>

rValue := reflect.ValueOf(r)

rType  := reflect.TypeOf(r)

fmt.Println("value:", rValue)

fmt.Println("type :", rType)

输出:

value: &{0xc04205a000} //指针

type : *os.File

var f float64

f = 1.234

fmt.Println("f value:",reflect.ValueOf(f))

fmt.Println("f type :",reflect.TypeOf(f))

输出:

f value: 1.234

f type : float64

2. Reflection goes from reflection object to interface value. 反射类型(reflect.Value,reflect.Type) --> 接口类型

type User struct {

   Id   int

   Name string

   Age  int

}

func (u User) ReflectCallFunc() {

   fmt.Println("reflect learn")

}

user := User{1, "test", 13}

var i interface{}

i = user

uValue := reflect.ValueOf(i)

uType  := reflect.TypeOf(i)

fmt.Println("uValue: ",uValue)

fmt.Println(uValue.Interface()) //转换为interface类型,unpack uValue.Interface().(User)

fmt.Println(uValue.Type())

fmt.Println("uValue,string: ",uType.String())

fmt.Println("uType: ",uType.Name())

for i := 0; i < uType.NumField(); i++ { //获取field信息

   field := uType.Field(i)

   value := uValue.Field(i).Interface()

   fmt.Printf("%s: %v = %v\n", field.Name, field.Type, value)

}

for i := 0; i < uType.NumMethod(); i++ {// 获取method信息

   method := uType.Method(i) 

   fmt.Printf("method[%d] = %s \n",i,method.Name)

}

fmt.Println(uValue.Kind())

fmt.Println(uType.Kind())

3. To modify a reflection object, the value must be settable. 通过反射修改变量

var x float64 = 3.4

v := reflect.ValueOf(x)

fmt.Println("settability of v:", v.CanSet()) //print: settability of v: false

v.SetFloat(7.1) // Error: will panic.

不可修改的原因:we pass a copy of x to reflect.ValueOf, so the interface value created as the argument to reflect.ValueOf is a copy of x, not x itself

解决办法,传递指针!!

var x float64 = 3.4

p := reflect.ValueOf(&x) // Note: take the address of x.

fmt.Println("type of p:", p.Type())

fmt.Println("settability of p:", p.CanSet())

print:

type of p: *float64

settability of p: false //why ? p不可set,p指向的内容可set,p指向的内容即*p,如何获得p指向的内容?

reflect.Value 的Elem方法,可以获取value 指向的内容

v := p.Elem()

fmt.Println("settability of v:", v.CanSet())//settability of v: true

v.SetFloat(7.1)

fmt.Println(v.Interface()) //7.1

fmt.Println(x)             //7.1

4. Structs 反射操作实例

type T struct {

   A int

   B string

}

t := T{23, "skidoo"}

s := reflect.ValueOf(&t).Elem()

typeOfT := s.Type()

for i := 0; i < s.NumField(); i++ {

   f := s.Field(i)

   fmt.Printf("%d:%v %s %s = %v\n", i, s.Kind(), typeOfT.Field(i).Name, f.Type(), f.Interface())

}

fmt.Println("canSet:",s.CanSet())

s.Field(0).SetInt(24)

s.Field(1).SetString("Sunset Strip")

fmt.Println("after change: ",s.Interface())

5. 通过reflect 来调用方法

type User struct {

   Id   int

   Name string

   Age  int

}

func (u User) ReflectCallFunc() {

   fmt.Println("reflect learn")

}

func (u User) FuncHasArgs(name string, age int) {

   fmt.Println("FuncHasArgs name: ", name, ", age:", age, "and origal User.Name:", u.Name)

}

func (u User) FuncNoArgs() {

   fmt.Println("FuncNoArgs")

}

user := User{1, "test", 13}

uValue := reflect.ValueOf(user)

uType  := reflect.TypeOf(user)

m1 := uValue.MethodByName("FuncHasArgs")

m2 := uValue.MethodByName("FuncNoArgs")

m ,b := uType.MethodByName("FuncNoArgs")

args := []reflect.Value{reflect.ValueOf("xiong"), reflect.ValueOf(30)}

m1.Call(args)

args = make([]reflect.Value,0)

m2.Call(args)

fmt.Println("m1:",m1)

fmt.Println("m2:",m2)

fmt.Printf("m:%#v,isfound:%v\n",m,b)

fmt.Println(m1)

©著作权归作者所有:来自51CTO博客作者暮色伊人的原创作品,如需转载,请注明出处,否则将追究法律责任


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消