Golang:使用reflect探究struct成员方法接收者指针
来源:互联网 发布:墨眉剑淘宝 编辑:程序博客网 时间:2024/06/14 17:03
问题背景
Go语言的面向对象在概念上与java大同小异,但是由于Go语言在给struct
添加method的时候需有一个显示的接收者(receiver),receiver可以是指针类型或是struct
的形参,二者到底有啥区别是在学习Go面向对象内容时最容易糊涂的地方。
问题描述
为了更好的阐述问题,首先撸上一段小代码:
//定义一个名为Controller的类type Controller struct { domain string count int}//给Controller添加第一个成员方法firstFuncfunc (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添加第二个成员方法secondFuncfunc (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字段值 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接口。
结语
本文为作者原创,如有错误还请指正,轻拍!
- Golang:使用reflect探究struct成员方法接收者指针
- Golang 使用reflect 更改struct内容
- Golang 方法的结构指针接收者和结构值接收者
- golang reflect简单使用
- golang json处理struct未导出成员
- golang recover from panic situation: - reflect: call of reflect.Value.Elem on struct Value
- golang struct结构体方法中的参数需要定义为指针类型
- golang struct结构体方法中的参数需要定义为指针类型
- 如何使用类的成员方法指针?
- 如何使用类的成员方法指针?
- 在C/C++中的struct使用函数指针,而且在C++中的struct还能使用成员函数
- &((struct*)0)->a与成员指针
- golang struct
- golang通过反射使用json字符串调用struct的指定方法及返回json结果
- golang 反射(reflect)
- [转]struct的初始化,拷贝及指针成员的使用技巧
- [C] struct的初始化,拷贝及指针成员的使用技巧
- golang里如何将一个struct指针转换成slice
- Android 自定义样式整理
- UVA
- 初识数据库
- branch方法更新github
- redis不同数据返回类型读取
- Golang:使用reflect探究struct成员方法接收者指针
- 在VMware中安装Linux(ubuntu)详…
- Windows下Python模块的安装
- Spring cloud oauth2.0学习总结
- spring aop
- 咖啡就是咖啡,不管放了多少糖,依然会有淡淡的苦
- 在C语言中利用PCRE实现正则表达式
- 编译原理―词法分析器(Java)
- com.sun.tools cannot be resolved