Skip to main content

Go struct method

Golang 方法集

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

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

在 Go 语言中,方法集(Method Set)是一个类型所拥有的方法的集合,它决定了该类型是否实现了某个接口。理解方法集对于正确使用接口和方法非常重要。下面我们详细解释一下你提供的规则,并举例说明。

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

这意味着如果一个方法的接收者是一个值类型(T),那么该方法只能属于 T 类型的值方法集。

package main

import "fmt"

type MyType struct{}

func (m MyType) ValueMethod() {
fmt.Println("Value method called")
}

func main() {
var v MyType
v.ValueMethod() // 可以调用
}

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

这意味着如果一个方法的接收者是一个指针类型(*T),那么该方法既属于 T 类型的值方法集,也属于 *T 类型的指针方法集。

package main

import "fmt"

type MyType struct{}

func (m MyType) ValueMethod() {
fmt.Println("Value method called")
}

func (m *MyType) PointerMethod() {
fmt.Println("Pointer method called")
}

func main() {
var v MyType
var p *MyType = &v

v.ValueMethod() // 可以调用
// v.PointerMethod() // 编译错误,值类型不能调用指针方法

p.ValueMethod() // 可以调用,指针类型可以调用值方法
p.PointerMethod() // 可以调用
}

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

如果类型 S 包含一个匿名字段 T,那么 S 和 *S 的方法集都包含 T 的值方法。

package main

import "fmt"

type T struct{}

func (t T) ValueMethod() {
fmt.Println("T's value method called")
}

type S struct {
T
}

func main() {
var s S
s.ValueMethod() // 可以调用,因为 S 的方法集包含 T 的方法

var ps *S = &s
ps.ValueMethod() // 可以调用,因为 *S 的方法集也包含 T 的方法
}

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

如果类型 S 包含一个匿名字段 *T,那么 S 和 *S 的方法集都包含 T 和 *T 的方法。

package main

import "fmt"

type T struct{}

func (t T) ValueMethod() {
fmt.Println("T's value method called")
}

func (t *T) PointerMethod() {
fmt.Println("T's pointer method called")
}

type S struct {
*T
}

func main() {
t := T{}
s := S{&t}

s.ValueMethod() // 可以调用,因为 S 的方法集包含 T 的方法
s.PointerMethod() // 可以调用,因为 S 的方法集包含 *T 的方法

var ps *S = &s
ps.ValueMethod() // 可以调用,因为 *S 的方法集包含 T 的方法
ps.PointerMethod() // 可以调用,因为 *S 的方法集包含 *T 的方法
}

5. 不管嵌入 T 或 *T,*S 方法集总是包含 T + *T 方法

无论是嵌入 T 还是 *T,*S 的方法集总是包含 T 和 *T 的方法。

package main

import "fmt"

type T struct{}

func (t T) ValueMethod() {
fmt.Println("T's value method called")
}

func (t *T) PointerMethod() {
fmt.Println("T's pointer method called")
}

type S1 struct {
T
}

type S2 struct {
*T
}

func main() {
t := T{}
s1 := S1{t}
s2 := S2{&t}

var ps1 *S1 = &s1
var ps2 *S2 = &s2

ps1.ValueMethod() // 可以调用,*S1 的方法集包含 T 的方法
ps1.PointerMethod() // 可以调用,*S1 的方法集包含 *T 的方法

ps2.ValueMethod() // 可以调用,*S2 的方法集包含 T 的方法
ps2.PointerMethod() // 可以调用,*S2 的方法集包含 *T 的方法
}

总结

  • 值类型 T 的方法集仅包含接收者为 T 的方法。
  • 指针类型 *T 的方法集包含接收者为 T 和 *T 的方法。
  • 如果类型 S 包含匿名字段 T 或 *T,S 和 *S 的方法集会包含相应的 T 和 *T 的方法。

这些规则帮助你理解如何定义和使用方法,以及如何通过嵌入字段来扩展类型的功能。

嵌入结构体方法提升 ⚡️

看上去像:相当于把子集方法,平铺到在父集方法中

alt text