博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Go语言_反射篇
阅读量:6191 次
发布时间:2019-06-21

本文共 5099 字,大约阅读时间需要 16 分钟。

这里的GO使用的版本是1.2

Go语言的基本语法的使用已经在前几篇陆陆续续学完了,下面可能想写一些Go的标准库的使用了。

先是reflect库。

reflect库的godoc在

Type和Value

首先,reflect包有两个数据类型我们必须知道,一个是Type,一个是Value。

Type就是定义的类型的一个数据类型,Value是值的类型

具体的Type和Value里面包含的方法就要看文档了:

 

这里我写了个程序来理解Type和Value:

package mainimport(    "fmt"    "reflect")type MyStruct struct{    name string}func (this *MyStruct)GetName() string {    return this.name}func main() {    s := "this is string"    fmt.Println(reflect.TypeOf(s))    fmt.Println("-------------------")        fmt.Println(reflect.ValueOf(s))    var x float64 = 3.4    fmt.Println(reflect.ValueOf(x))    fmt.Println("-------------------")        a := new(MyStruct)    a.name = "yejianfeng"    typ := reflect.TypeOf(a)    fmt.Println(typ.NumMethod())    fmt.Println("-------------------")        b := reflect.ValueOf(a).MethodByName("GetName").Call([]reflect.Value{})    fmt.Println(b[0])}

输出结果:

string-------------------this is string
-------------------1-------------------yejianfeng

 

补充,在Go version 1.5中会返回

string-------------------this is string3.4-------------------1-------------------yejianfeng

  

这个程序看到几点:

1 TypeOf和ValueOf是获取Type和Value的方法

2 第三个b的定义实现了php中的string->method的方法,为什么返回的是reflect.Value[]数组呢?当然是因为Go的函数可以返回多个值的原因了。

Value的方法和属性

好了,我们看到Value的Type定义了这么多Set方法:

下面看这么个例子:

package mainimport(    "fmt"    "reflect")type MyStruct struct{    name string}func (this *MyStruct)GetName() string {    return this.name}func main() {    fmt.Println("--------------")    var a MyStruct    b := new(MyStruct)    fmt.Println(reflect.ValueOf(a))    fmt.Println(reflect.ValueOf(b))        fmt.Println("--------------")    a.name = "yejianfeng"    b.name = "yejianfeng"    val := reflect.ValueOf(a).FieldByName("name")    //painc: val := reflect.ValueOf(b).FieldByName("name")    fmt.Println(val)    fmt.Println("--------------")    fmt.Println(reflect.ValueOf(a).FieldByName("name").CanSet())    fmt.Println(reflect.ValueOf(&(a.name)).Elem().CanSet())        fmt.Println("--------------")    var c string = "yejianfeng"    p := reflect.ValueOf(&c)    fmt.Println(p.CanSet())   //false    fmt.Println(p.Elem().CanSet())  //true    p.Elem().SetString("newName")    fmt.Println(c)}

返回:

 

这段代码能有一些事情值得琢磨:

1 为什么a和b的ValueOf返回的是不一样的?

a是一个结构,b是一个指针。好吧,在Go中,指针的定义和C中是一样的。

2 reflect.ValueOf(a).FieldByName("name")

这是一个绕路的写法,其实和a.name是一样的意思,主要是要说明一下Value.FieldByName的用法

3 val := reflect.ValueOf(b).FieldByName("name") 是有error的,为什么?

b是一个指针,指针的ValueOf返回的是指针的Type,它是没有Field的,所以也就不能使用FieldByName

4 fmt.Println(reflect.ValueOf(a).FieldByName("name").CanSet())为什么是false?

看文档中的解释:

好吧,什么是addressable,and was not obtained by the use of unexported struct fields?

CanSet当Value是可寻址的时候,返回true,否则返回false

看到第二个c和p的例子,我们可以这么理解:

当前面的CanSet是一个指针的时候(p)它是不可寻址的,但是当是p.Elem()(实际上就是*p),它就是可以寻址的

这个确实有点绕。

 

总而言之,reflect包是开发过程中几乎必备的包之一。能合理和熟练使用它对开发有很大的帮助。

 

20160829 补充:

Go 1.5的reflect Type方法可以看下面这个例子:

package mainimport (	"fmt"	"reflect")type MyStruct struct {	name string}func (this *MyStruct) GetName() string {	return this.name}type IStruct interface {	GetName() string}func main() {	// TypeOf	s := "this is string"	fmt.Println(reflect.TypeOf(s)) // output: "string"	// object TypeOf	a := new(MyStruct)	a.name = "yejianfeng"	typ := reflect.TypeOf(a)	fmt.Println(typ)        // output: "*main.MyStruct"	fmt.Println(typ.Elem()) // output: "main.MyStruct"	// reflect.Type Base struct	fmt.Println(typ.NumMethod())                   // 1	fmt.Println(typ.Method(0))                     // {GetName  func(*main.MyStruct) string 
0} fmt.Println(typ.Name()) // "" fmt.Println(typ.PkgPath()) // "" fmt.Println(typ.Size()) // 8 fmt.Println(typ.String()) // *main.MyStruct fmt.Println(typ.Elem().String()) // main.MyStruct fmt.Println(typ.Elem().FieldByIndex([]int{0})) // {name main string 0 [0] false} fmt.Println(typ.Elem().FieldByName("name")) // {name main string 0 [0] false} true fmt.Println(typ.Kind() == reflect.Ptr) // true fmt.Println(typ.Elem().Kind() == reflect.Struct) // true fmt.Println(typ.Implements(reflect.TypeOf((*IStruct)(nil)).Elem())) // true fmt.Println(reflect.TypeOf(12.12).Bits()) // 64, 因为是float64 cha := make(chan int) fmt.Println(reflect.TypeOf(cha).ChanDir()) // chan var fun func(x int, y ...float64) string var fun2 func(x int, y float64) string fmt.Println(reflect.TypeOf(fun).IsVariadic()) // true fmt.Println(reflect.TypeOf(fun2).IsVariadic()) // false fmt.Println(reflect.TypeOf(fun).In(0)) // int fmt.Println(reflect.TypeOf(fun).In(1)) // []float64 fmt.Println(reflect.TypeOf(fun).NumIn()) // 2 fmt.Println(reflect.TypeOf(fun).NumOut()) // 1 fmt.Println(reflect.TypeOf(fun).Out(0)) // string mp := make(map[string]int) mp["test1"] = 1 fmt.Println(reflect.TypeOf(mp).Key()) //string arr := [1]string{"test"} fmt.Println(reflect.TypeOf(arr).Len()) // 1 fmt.Println(typ.Elem().NumField()) // 1 // MethodByName, Call b := reflect.ValueOf(a).MethodByName("GetName").Call([]reflect.Value{}) fmt.Println(b[0]) // output: "yejianfeng"}

 

转载地址:http://syrda.baihongyu.com/

你可能感兴趣的文章
eclipse 不能启动虚拟机
查看>>
为什么要搭建自己的缓存管理模块?
查看>>
苏州Uber优步司机奖励政策(8月31日至9月6日)
查看>>
[DEEP LEARNING An MIT Press book in preparation]Linear algebra
查看>>
读书笔记:《重来REWORK》
查看>>
Codeforces Round #321 (Div. 2) B. Kefa and Company 二分
查看>>
在Visual Studio 2013顯示SCSS詳細錯誤訊息
查看>>
经典问题(1)
查看>>
LeetCode——Linked List Cycle
查看>>
Swift - .plist文件数据的读取和存储
查看>>
Eclipse中设置JDK内存方式
查看>>
流程引擎Activiti系列:在eclipse中搭建咖啡兔的Activiti演示工程中的各种坑及其解决方法(kft-activiti-demo-no-maven)...
查看>>
[AngularJS] Enable Animations Explicitly For A Performance Boost In AngularJS
查看>>
Android接口回调机制
查看>>
同一个form里,不管哪个 submit 都是直接提交form表单里的内容
查看>>
GEOS库的学习之一:介绍和编译
查看>>
Eclipse修改Tomcat发布路径以及的配置多个Tomcat方法
查看>>
Swift 中类的初始化器与继承
查看>>
iptables 问题
查看>>
url-pattern
查看>>