1. 方法集

Golang方法集 :每个类型都有与之关联的方法集,这会影响到接口实现规则。

  1. 类型 T 方法集包含全部 receiver T 方法。
  2. 类型 *T 方法集包含全部 receiver T + *T 方法。
  3. 如类型 S 包含匿名字段 T,则 S *S 方法集包含 T 方法。
  4. 如类型 S 包含匿名字段 *T,则 S *S 方法集包含 T + *T 方法。
  5. 不管嵌入 T *T,*S 方法集总是包含 T + *T 方法。

用实例 value 和 pointer 调用方法 (含匿名字段) 不受方法集约束,编译器总是查找全部方法,并自动转换 receiver 实参。

Go 语言中内部类型方法集提升的规则:

类型 T 方法集包含全部 receiver T 方法。

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. type T struct {
  6. int
  7. }
  8. func (t T) test() {
  9. fmt.Println("类型 T 方法集包含全部 receiver T 方法。")
  10. }
  11. func main() {
  12. t1 := T{1}
  13. fmt.Printf("t1 is : %v\n", t1)
  14. t1.test()
  15. }

输出结果:

  1. t1 is : {1}
  2. 类型 T 方法集包含全部 receiver T 方法。

类型 *T 方法集包含全部 receiver T + *T 方法。

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. type T struct {
  6. int
  7. }
  8. func (t T) testT() {
  9. fmt.Println("类型 *T 方法集包含全部 receiver T 方法。")
  10. }
  11. func (t *T) testP() {
  12. fmt.Println("类型 *T 方法集包含全部 receiver *T 方法。")
  13. }
  14. func main() {
  15. t1 := T{1}
  16. t2 := &t1
  17. fmt.Printf("t2 is : %v\n", t2)
  18. t2.testT()
  19. t2.testP()
  20. }

输出结果:

  1. t2 is : &{1}
  2. 类型 *T 方法集包含全部 receiver T 方法。
  3. 类型 *T 方法集包含全部 receiver *T 方法。

给定一个结构体类型 S 和一个命名为 T 的类型,方法提升像下面规定的这样被包含在结构体方法集中:

如类型 S 包含匿名字段 T,则 S 和 *S 方法集包含 T 方法。

这条规则说的是当我们嵌入一个类型,嵌入类型的接受者为值类型的方法将被提升,可以被外部类型的值和指针调用。

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. type S struct {
  6. T
  7. }
  8. type T struct {
  9. int
  10. }
  11. func (t T) testT() {
  12. fmt.Println("如类型 S 包含匿名字段 T,则 S 和 *S 方法集包含 T 方法。")
  13. }
  14. func main() {
  15. s1 := S{T{1}}
  16. s2 := &s1
  17. fmt.Printf("s1 is : %v\n", s1)
  18. s1.testT()
  19. fmt.Printf("s2 is : %v\n", s2)
  20. s2.testT()
  21. }

输出结果:

  1. s1 is : {{1}}
  2. 如类型 S 包含匿名字段 T,则 S *S 方法集包含 T 方法。
  3. s2 is : &{{1}}
  4. 如类型 S 包含匿名字段 T,则 S *S 方法集包含 T 方法。

如类型 S 包含匿名字段 *T,则 S 和 *S 方法集包含 T + *T 方法。

这条规则说的是当我们嵌入一个类型的指针,嵌入类型的接受者为值类型或指针类型的方法将被提升,可以被外部类型的值或者指针调用。

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. type S struct {
  6. T
  7. }
  8. type T struct {
  9. int
  10. }
  11. func (t T) testT() {
  12. fmt.Println("如类型 S 包含匿名字段 *T,则 S 和 *S 方法集包含 T 方法")
  13. }
  14. func (t *T) testP() {
  15. fmt.Println("如类型 S 包含匿名字段 *T,则 S 和 *S 方法集包含 *T 方法")
  16. }
  17. func main() {
  18. s1 := S{T{1}}
  19. s2 := &s1
  20. fmt.Printf("s1 is : %v\n", s1)
  21. s1.testT()
  22. s1.testP()
  23. fmt.Printf("s2 is : %v\n", s2)
  24. s2.testT()
  25. s2.testP()
  26. }

输出结果:

  1. s1 is : {{1}}
  2. 如类型 S 包含匿名字段 *T,则 S *S 方法集包含 T 方法
  3. 如类型 S 包含匿名字段 *T,则 S *S 方法集包含 *T 方法
  4. s2 is : &{{1}}
  5. 如类型 S 包含匿名字段 *T,则 S *S 方法集包含 T 方法
  6. 如类型 S 包含匿名字段 *T,则 S *S 方法集包含 *T 方法