Go中的方法
Go 语言从设计之初,就不支持经典的面向对象语法元素,比如类、对象、继 承,等等,但 Go 语言仍保留了名为“方法(method)”的语法元素。当然,Go 语言中 的方法和面向对象中的方法并不是一样的
方法的定义
go中方法的定义和函数的定义很像
1 | type People struct { |
1 | func (t *T或T) MethodName(参数列表) (返回值列表) { |
和函数最大的不同就是这个receiver部分。这个receiver部分是一个类型。作用是指明这个方法的归属。就可以说这个类型有这样一个方法。
每个方法只能有一个 receiver 参数
receiver 参数的基类型本身不能为指针类型或接口类型
Go 要求,方法声明要与 receiver 参数的基 类型声明放在同一个包内。也就是说我们不能给go的原生类型(比如int,string)等添加方法,也不能给其他包的类型添加方法。
方法的本质是函数
java的方法在调用时,实际上编译器会自动将this作为第一参数传入方法中。go的原理也类似。
所以上面的
1 | func (p People) String() string { |
可以转换为函数
1 | func String(p People) string { |
这种等价转换后的函数的类型就是方法的类型
所以,Go 语言中的方法的本质就是,一个以方法的 receiver 参数 作为第一个参数的普通函数。
receiver的类型选择问题
首先看这个例子
1 |
|
结果
1 | =======:{alex google} |
两个set方法,一个的receiver是类型,一个是类型指针。
之前就说过Go 函数的参数采用的是值拷贝传递,SetName中对receiver的修改,只会影响e的副本,不会影响e本身。
类型是*Employee的setCompany方法,因为传递的是地址,所以会影响。
所以,选择receiver类型的原则:
如果需要将修改反应在原实例上,用*T
无论是 T 类型实例,还是 *T 类型实例,都既 可以调用 receiver 为 T 类型的方法,也可以调用 receiver 为 *T 类型的方法。这是go的语法糖自动转换
还是因为值拷贝问题,用T作为receiver类型,如果实例很大,会有较大的性能开销,这种情况下还是用*T比较好
根据T类型是否需要实现某个接口。是,则需要使用T类型作为receiver。
另外Go 语言规定,*T 类型的方法集合包含所有以 *T 为 receiver 参数类型的方 法,以及所有以 T 为 receiver 参数类型的方法。