36、Go 结构体 - 面向对象之方法集

作者: 温新

分类: 【Go基础】

阅读: 280

时间: 2023-12-05 00:29:44

hi,我是温新

什么是方法集

在go语言中,每个类型都有与之关联的方法,把这个类型的所有方法称为类型的方法集。

来看个简单的案例:

package main

import "fmt"

func main() {
	s2 := &Students{"王小丽", 18}
	s2.showName()
	
}

type Students struct {
	name string
	age  int8
}

func (s Students) showName() {
	fmt.Println(s.name)
}

func (s *Students) setName(name string) {
	s.name = name
}

类型 Students 方法集包含了 ShowName 方法;

类型 *Students 方法集包含了 ShowName 和 SetName 方法。为什么会是这样,来看看方法集的规则,如下:

类型 方法参数接收类型
T (t T)
*T (t T) and (t *T)

这个规则是什么意思呢?如下:

  • 类型 T 方法集包含全部 receiver T 方法;
  • 类型 *T 方法集包含全部 receiver T + *T 方法;
  • 若类型 S 包含匿名字段 T,则 S 和 *S 方法集包含 T 方法;
  • 若类型 S 包含匿名字段 *T,则 S 和 *S 方法集包含 T + *T 方法;
  • 不管是嵌套 T 还是 *T, *S 方法集总是包含 T + *T 方法。

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

方法集案例

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

package main

import "fmt"

func main() {
	t1 := T{1}
	fmt.Printf("t1 is : %v\n", t1)
	t1.test()
}

type T struct {
	int
}

func (t T) test() {
	fmt.Println("类型 T 方法集包含全部 receiver T 方法。")
}

输出结果:

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

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

package main

import "fmt"

func main() {
	t1 := Ty{1}
    // 指针赋值
	t2 := &t1
	fmt.Printf("t2 是:%v\n", t2)
	t2.testT()
	t2.testP()
}

type Ty struct {
	int
}

func (t Ty) testT() {
	fmt.Println("类型 *Ty 方法集包含全部 receiver Ty 方法。")
}

func (t *Ty) testP() {
	fmt.Println("类型 *Ty 方法集包含全部 receiver *Ty 方法。")
}

输出结果

t2 是:&{1}
类型 *Ty 方法集包含全部 receiver Ty 方法。
类型 *Ty 方法集包含全部 receiver *Ty 方法。

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

package main

import "fmt"

func main() {
	s1 := S{T1{1}}
	s2 := &s1
	fmt.Printf("s1 是 %v\n", s1)
	s1.testT()
	fmt.Printf("s2 是 %v\n", s2)
	s2.testT()
}

type T1 struct {
	int
}

type S struct {
	T1
}

func (t T1) testT() {
	fmt.Println("如类型 S 包含匿名字段 T1,则 S 和 *S 方法集包含 T1 方法。")
}

输出结果:

s1 是 {{1}}
如类型 S 包含匿名字段 T1,则 S 和 *S 方法集包含 T1 方法。
s2 是 &{{1}}
如类型 S 包含匿名字段 T1,则 S 和 *S 方法集包含 T1 方法。

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

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

package main

import "fmt"

func main() {
	s1 := S1{T2{1}}
	s2 := &s1
	fmt.Printf("s1 is : %v\n", s1)
	s1.testT()
	s1.testP()
	fmt.Printf("s2 is : %v\n", s2)
	s2.testT()
	s2.testP()
}

type T2 struct {
	int
}

type S1 struct {
	T2
}

func (t T2) testT() {
	fmt.Println("如类型 S1 包含匿名字段 *T2,则 S1 和 *S1 方法集包含 T2 方法")
}

func (t *T2) testP() {
	fmt.Println("如类型 S1 包含匿名字段 *T,则 S1 和 *S1 方法集包含 *T2 方法")
}

输出结果如下:

s1 is : {{1}}
如类型 S1 包含匿名字段 *T2,则 S1 和 *S1 方法集包含 T2 方法
如类型 S1 包含匿名字段 *T,则 S1 和 *S1 方法集包含 *T2 方法
s2 is : &{{1}}
如类型 S1 包含匿名字段 *T2,则 S1 和 *S1 方法集包含 T2 方法
如类型 S1 包含匿名字段 *T,则 S1 和 *S1 方法集包含 *T2 方法

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

请登录后再评论