Golang:使用reflect探究struct成员方法接收者指针
2017-04-14 21:08
417 查看
问题背景
Go语言的面向对象在概念上与java大同小异,但是由于Go语言在给struct添加method的时候需有一个显示的接收者(receiver),receiver可以是指针类型或是
struct的形参,二者到底有啥区别是在学习Go面向对象内容时最容易糊涂的地方。
问题描述
为了更好的阐述问题,首先撸上一段小代码://定义一个名为Controller的类 type Controller struct { domain string count int } //给Controller添加第一个成员方法firstFunc func (c *Controller) firstFunc(domain string, count int) { c.domain = domain c.count = count fmt.Println("firstFunc's domain is "+c.domain+" count is ", c.count) } //给Controller添加第二个成员方法secondFunc func (c Controller) secondFunc(domain string, count int) { c.domain = domain c.count = count fmt.Println("secondFunc's domain is "+c.domain+" count is ", c.count) }
如上,在Go中定义类用
struct类型,在Controller类有两个field,分别为
domian和
count,还添加了两个方法,分别是
firstFunc(domain string, count int)和
secondFunc(domain string, count int),不同的是firstFunc的receiver是Controller的指针而secondFunc传入的receiver是Controller的形参。那么问题来了不同类型的receiver具体会有哪些区别呢?下面将以笔者拙见进行总结归纳,分享之余也用于给自己记录。
问题解答
对类字段值修改结果不同这个问题根据指针的意义就能理解,receiver为指针时相当于类的引用,
*Controller.domain=domain修改了Controller中domain字段的值,receiver为形参时,相当于Controller类的一个copy值,因此
Controller.domain=domain只是修改了Controller的一个副本的字段值,并非原Controller本身字段值。代码验证如下:
func main() { //创建一个名为controller的Controller实体指针并初始化字段值 controller := &Controller{ domain: "www.baidu.com", count: 1000, } //输出controller原始字段值 fmt.Println("conroller's original domain is <"+controller.domain+"> count is ", controller.count) //调用firstFunc并查看controller字段值 controller.firstFunc("www.sohu.com", 500) fmt.Println("firstFunc>conroller's domain is <"+controller.domain+"> count is ", controller.count) //调用secondFunc并查看controller字段 4000 值 controller.secondFunc("www.qq.com", 800) fmt.Println("secondFunc>conroller's domain is <"+controller.domain+"> count is ", controller.count) }
运行结果如下:
Controller实例与Controller实例指针包含方法不同
简单概括来讲,类的实例指针(也就是上一段代码中的controller)包含所有方法,即在以上代码中controller包含firstFunc和secondFunc两个方法,而实例只包含receiver为形参的方法,即若controller不是指针则firstFunc是不能够被成功调用的,因为其receiver为指针。为了能够更加直观的进行说明,下面用reflect反射机制进行验证:
func main() { //初始化一个类指针controller1 controller1 := &Controller{ domain: "www.baidu.com", count: 1000, } //初始化一个类controller2 controller2 := Controller{ domain: "www.sohu.com", count: 800, } t1 := reflect.TypeOf(controller1) //查看controller1的类型与包含的方法个数 fmt.Println("controller1's type is", t1.Kind(), "include", t1.NumMethod(), "methods") //查看controller1的所有方法名称 for j := 0; j < t1.NumMethod(); j++ { fmt.Println(++j,t1.Method(j).Name) } //查看controller2的类型与包含的方法个数 fmt.Println("controller2's type is", t2.Kind(), "include", t2.NumMethod(), "methods") //查看controller2的所有方法名称 for j := 0; j < t2.NumMethod(); j++ { fmt.Println(t2.Method(j).Name) } }
执行结果如下:
对接口实现的区别
接口通常会规定一些方法,实现了这些方法的类就相当于实现了相应接口,类方法的receiver是否为指针对接口实现的影响主要还在于类是否包含接口规定的所有方法。现定义一个接口:
type ControllerInter interface { firstFunc(domain string, count int) secondFunc(domain string, count int) }
在上一问题验证代码中controller1因为包含了ControllerInter规定的所有方法,因此实现了该接口,而controller则没有实现。因此在判断类是否实现了某一接口时要特别注意其成员方法的receiver类型以及类的类型,尽管结果已经很清晰,但同样还是用代码加以验证:
func main() { controller1 := &Controller{ domain: "www.baidu.com", count: 1000, } controller2 := Controller{ domain: "www.sohu.com", count: 800, } var controllerInter ControllerInter controllerInter = controller1 controllerInter = controller2 }
执行结果如下:
声明一个名为controllerInter的接口变量,并将controller1和controller2一次复制给它,实现了接口的将顺利执行,没有实现的将会报错,如上图中controller2 does not implement ControllerInter接口。
结语
本文为作者原创,如有错误还请指正,轻拍!相关文章推荐
- [转]struct的初始化,拷贝及指针成员的使用技巧
- struct的初始化,拷贝及指针成员的使用技巧
- [C] struct的初始化,拷贝及指针成员的使用技巧
- C++ MFC 其他函数获得主对话框指针并使用成员的方法
- golang通过反射使用json字符串调用struct的指定方法及返回json结果
- 如何使用类的成员方法指针?
- Golang 使用reflect 更改struct内容
- 类的成员函数指针的使用方法
- Golang 方法的结构指针接收者和结构值接收者
- 类的成员函数指针的使用方法
- C++ MFC 其他函数获得主对话框指针并使用成员的方法
- C++成员函数指针的使用方法
- 如何使用类的成员方法指针?
- struct的初始化,拷贝及指针成员的使用技巧(摘自http://blog.chinaunix.net/u/9577/showart_417268.html)
- struct也有方法成员
- 如何得到类成员函数的指针(操作符.×和->*的使用)
- C++指向类成员的指针的使用(详细介绍)
- power point2003中播放幻灯片无法使用绘图笔指针的解决方法
- 使用java反射操作类的构造函数,成员变量和成员方法
- Unmanaged Code和Managed Code混合编程中使用COM接口指针的一种方法