-
方法定义:
func (接收者变量 接收者类型) 方法名(参数列表) (返回值列表) { 函数体 }
-
Go 语言中的方法的本质就是,一个以方法的 receiver 参数作为第一个参数的普通函数。这个 receiver 参数也是方法与类型之间的纽带,也是方法与函数的最大不同。Go 中的方法必须是归属于一个类型的,而 receiver 参数的类型就是这个方法归属的类型,或者说这个方法就是这个类型的一个方法。
-
方法与函数的区别是,函数不属于任何类型,方法属于特定的类型。
-
每个方法只能有一个 receiver 参数,Go 不支持在方法的 receiver 部分放置包含多个 receiver 参数的参数列表,或者变长 receiver 参数。
-
方法接收器(receiver)参数、函数 / 方法参数,以及返回值变量对应的作用域范围,都是函数 / 方法体对应的显式代码块
-
receiver 参数的基类型本身不能为指针类型或接口类型。
-
方法声明要与 receiver 参数的基类型声明放在同一个包内。
-
方法集合也是用来判断一个类型是否实现了某接口类型的唯一手段,可以说,“方法集合决定了接口实现”。
选择 receiver 参数类型的原则
-
receiver 参数的类型:
- 当 receiver 参数的类型为 T 时,M1 方法等价转换为F1(t T)。我们知道,Go 函数的参数采用的是值拷贝传递,也就是说,F1 函数体中的 t 是 T 类型实例的一个副本。这样,我们在 F1 函数的实现中对参数 t 做任何修改,都只会影响副本,而不会影响到原 T 类型实例。
- 当 receiver 参数的类型为 *T 时:同上面分析,我们传递给 F2 函数的 t 是 T 类型实例的地址,这样 F2 函数体中对参数 t 做的任何修改,都会反映到原 T 类型实例上。实际上是 T 类型实例的地址,M2 方法体通过该地址可以对原 T 类型实例进行任何修改操作。
-
什么时候应该使用指针类型接收者:
- 需要修改接收者中的值
- 接收者是拷贝代价比较大的大对象
- 保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者
-
选择 receiver 参数类型的第一个原则:
- 如果 Go 方法要把对 receiver 参数代表的类型实例的修改,反映到原类型实例上,那么我们应该选择 *T 作为 receiver 参数的类型。
- 无论是 T 类型实例,还是 *T 类型实例,都既可以调用 receiver 为 T 类型的方法,也可以调用 receiver 为 *T 类型的方法。
-
选择 receiver 参数类型的第二个原则
- 我们通常会为 receiver 参数选择 T 类型,因为这样可以缩窄外部修改类型实例内部状态的“接触面”,也就是尽量少暴露可以修改类型内部状态的方法。
- 考虑到 Go 方法调用时,receiver 参数是以值拷贝的形式传入方法中的。那么,如果 receiver 参数类型的 size 较大,以值拷贝形式传入就会导致较大的性能开销,这时我们选择 *T 作为 receiver 类型可能更好些。
-
Go 语言规定,*T 类型的方法集合包含所有以 *T 为 receiver 参数类型的方法,以及所有以 T 为 receiver 参数类型的方法。
独立的自定义类型
Go 语言支持两种类型嵌入,分别是接口类型的类型嵌入和结构体类型的类型嵌入。
- 接口类型的类型嵌入
- 接口类型嵌入的语义就是新接口类型(如接口类型 I)将嵌入的接口类型(如接口类型 E)的方法集合,并入到自己的方法集合中。