3.4 KiB
3.4 KiB
方法
package main
import "fmt"
type T struct{}
func (t *T) M(n int) {
fmt.Println(n)
}
func (t T)N(n int) {
fmt.Println(n)
}
func main() {
m1 := (*T).M
m1(&T{}, 2)
m2 := T.N
m2(T{}, 3)
}
方法接收receiver
func (t *T或T) MethodName(参数列表) (返回值列表) {
// 方法体
}
- T为基类型
- receiver 参数的基类型本身不能为指针类型或接口类型
- 每个方法只能有一个 receiver 参数
- Go 不支持在方法的 receiver 部分放置包含多个 receiver 参数的参数列表,或者变长 receiver 参数
- 方法接收器(receiver)参数、函数 / 方法参数,以及返回值变量对应的作用域范围,都是函数 / 方法体对应的显式代码块
- receiver 部分的参数名不能与方法参数列表中的形参名,以及具名返回值中的变量名存在冲突,必须在这个方法的作用域中具有唯一性
- 如果在方法体中,我们没有用到 receiver 参数,我们也可以省略 receiver 的参数名
方法声明约束
- 方法声明要与 receiver 参数的基类型声明放在同一个包内
- 不能为原生类型(诸如 int、float64、map 等)添加方法
- 不能跨越 Go 包为其他包的类型声明新方法
选择receiver 原则
- 如果需要修改receiver内部属性,使用指针类型
- 不需要修改内部属性,使用结构体类型,传参值拷贝,但是结构体过大时,选用指针类型
- 如果 T 类型需要实现某个接口,那就要使用 T 作为 receiver 参数的类型,来满足接口类型方法集合中的所有方法
方法集合
- 用来判断一个类型是否实现了某接口类型的唯一手段
- T类型实现了M1方法
- *T类型实现了M1和M2方法
type Interface interface {
M1()
M2()
}
type T struct{}
func (t T) M1() {}
func (t *T) M2() {}
func main() {
var t T
var pt *T
var i Interface
i = pt
i = t // cannot use t (type T) as type Interface in assignment: T does not implement Interface (M2 method has pointer receiver)
}
type定义的新类型和命名的类型的方法集合
- 自定义非接口类型的 defined 类型的方法集合为空
- 自定义接口类型的 defined 类型的方法集合为接口的方法
package main
type T struct{}
func (T) M1() {}
func (*T) M2() {}
type T1 T
func main() {
var t T
var pt *T
var t1 T1
var pt1 *T1
dumpMethodSet(t)
dumpMethodSet(t1)
dumpMethodSet(pt)
dumpMethodSet(pt1)
}
main.T's method set:
- M1
main.T1's method set is empty!
*main.T's method set:
- M1
- M2
*main.T1's method set is empty!
- 无论原类型是接口类型还是非接口类型,类型别名都与原类型拥有完全相同的方法集合
type T struct{}
func (T) M1() {}
func (*T) M2() {}
type T1 = T
func main() {
var t T
var pt *T
var t1 T1
var pt1 *T1
dumpMethodSet(t)
dumpMethodSet(t1)
dumpMethodSet(pt)
dumpMethodSet(pt1)
}
main.T's method set:
- M1
main.T's method set:
- M1
*main.T's method set:
- M1
- M2
*main.T's method set:
- M1
- M2