1. 概念
首先我们要知道 golang 中一个类型加上它的方法等价于面向对象(c++/java)中的一个类,那么一切就很好理解了。
我们把方法依附的主体称为接收者(等价于对象),接收者是某种类型的变量(不仅仅限于结构体)。
Go 方法是作用在接收者(receiver)上的一个函数. 因此方法是一种特殊类型的函数。
接收者类型可以是(几乎)任何类型, 但是:
不能是一个接口类型, (因为接口是抽象定义, 但是方法是具体实现)
不能是一个指针类型,但是它可以是任何其他允许类型的指针。
类型 T(或 *T)上的所有方法的集合叫做类型 T(或 *T)的方法集(method set)。
因为方法是函数,所以不允许重载,即对于一个类型只能有一个给定名称的方法。
但是基于不同的接收者类型,可以拥有相同名称的方法.
别名类型没有原始类型上已经定义过的方法。
2. 定义
在方法名之前,func
关键字之后的括号中指定 receiver.
我们可以看到 recv 其实类似于 self 或者是 this 指针
func (recv receiver_type) methodName1(parameter_list) (return_value_list) {
//todo
}
//考虑到效率的问题, 建议使用这样的方式
func (recv *receiver_type) methodName2(parameter_list) (return_value_list) {
//todo
}
3. 函数和方法的区别
1. 定义方式不同
2. 调用方式不同
函数将变量作为参数:Function1(recv)
方法在变量上被调用:recv.Method1()
3. 改变参数/接收者的值
在接收者是指针时,方法可以改变接收者的值(或状态),
函数也可以做到(当参数作为指针传递,即通过引用调用时,函数也可以改变参数的状态)。
4. 方法没有和数据定义(结构体)混在一起:他们分别表示(数据)和行为(方法), 是独立的。
注意:
1. 鉴于性能的原因,建议写指针方法 (非必须)
2. 指针方法和值方法都可以在指针或非指针上被调用
3. 我们可以对外提供方法来获取/修改某些私有的成员值
4. 继承
我们可以把内部结构体类型视为父类,外部结构体则可以继承父类的方法,但是根据继承方式不同使用上有所区别。
聚合:包含一个所需功能类型的具名字段,只能使用结构体内部的命名变量来调用父类方法
内嵌:内嵌(匿名地)所需功能类型,匿名类型的可见方法可以被直接使用,这在效果上等同于继承(将父类型放在子类型中来实现亚型);和内嵌类型方法具有同样名字的外层类型的方法会覆写内嵌类型对应的方法
多重继承:通过在类型中嵌入所有必要的父类型,可以很简单的实现多重继承。
总结
类型就是类(数据和关联的方法)。
代码复用通过组合和委托实现,多态通过接口的使用来实现:有时这也叫 组件编程(Component Programming)。
备注
如果真的需要更多面向对象的能力,看一下 goop
包(Go Object-Oriented Programming),它由 Scott Pakin 编写: 它给 Go 提供了 JavaScript 风格的对象(基于原型的对象),并且支持多重继承和类型独立分派,通过它可以实现你喜欢的其他编程语言里的一些结构。