- 方法所属的类型并不一定是结构体类型,必须是某个自定义的数据类型,但不能是任何接口类型或接口的指针类型。
给一个函数类型 FuncJob
定义一个方法 func (f *FuncJob) Run()
type FuncJob func()
func (f *FuncJob) Run() {
fmt.Println("job exe ....")
}
-
一个数据类型关联的所有方法,共同组成了该类型的方法集合。
-
同一个方法集合中的方法不能出现重名。
-
结构体类型的方法:
- 结构体类型的方法名称与结构体中任何字段的名称(包括成员变量名称)都不能重复。
-
结构体嵌入的时候,会出现方法屏蔽现象:
- 结构体
Dog
嵌入了结构体Animal
, 结构体Animal
嵌入了结构体Object
。Dog
实现了与Animal
相同名字的方法Eat
(只要方法名一样,不管方法签名),Dog
直接调用Eat
方法是调用的Dog
的,Animal
的Eat
方法被屏蔽了。
- 结构体
Cat
嵌入了结构体Animal
, 结构体Animal
嵌入了结构体Object
。Dog
可以直接调用Animal
的Eat
方法。
Dog
和Eat
都可以通过链式的点语法(.
)来调用Animal
的Eat
方法。 (eg:d.Animal.Eat()
、c.Animal.Eat()
)
- 结构体
-
多级嵌入方法屏蔽也是一样的,里层的会被外层的屏蔽掉。
-
成员变量名和方法名相同,成员变量名和成员变量名,也会被屏蔽掉。
-
Go 通过嵌入字段的方式实现了类型之间的组合。(组合是非声明式的,不需要显示的声明某个类型实现了某个接口,不需要一个类型继承了另一个类型)
-
通过嵌入字段实现:把一个类型的属性和操作给另一个类型,被嵌入类型也就实现了嵌入字段所实现的接口。
type Object struct {
}
type Animal struct {
Object
}
func (p *Animal) Eat() {
fmt.Println("animal eat")
}
type Dog struct {
Animal
}
func (p *Dog) Eat() {
fmt.Println("dog eat")
}
type Cat struct {
Animal
}
func main() {
//Animal 的方法 Eat,被 Dog 的 Eat 方法屏蔽了,或者直接使用点方法调用 Animal 的方法 Eat
d := &Dog{}
d.Eat()
d.Animal.Eat()
//Cat 可以直接调用嵌入类型 Animal 的方法 Eat,或者直接使用点方法调用 Animal 的方法 Eat
c := &Cat{}
c.Eat()
c.Animal.Eat()
}
方法 func (p *Dog) Eat()
就是一个指针方法。方法接收者是指针类型。
方法 func (p Dog) Run()
就是一个值方法。方法接收者是值类型(非指针类型)(可能是引用类型切片、字典等)。
func (p *Dog) Eat() {
fmt.Println("dog eat")
}
func (p Dog) Run() {
fmt.Println("dog eat")
}
-
对接收者修改:
- 值方法的接收者是值的一个副本(该接收者非引用类型),在方法内部修改接收者不会修改原值。
- 指针方法接收者是指针的一个副本,方法内部修改的是副本指针指向的值,会修改原值。
-
调用:
- 指针类型的方法集合包括了所有的指针方法和所有的值方法。一个自定义数据类型的方法集合(即值方法集合)中只包含所有值方法。
- 指针变量不仅可以调用指针方法,也可以调用值方法
- 值变量不仅可以调用值方法,也可以调用指针方法 。(Go语言会自动使用该值变量的指针调用指针方法)
-
基本类型和它的指针类型的方法集合是不同的,它们具体实现的接口类型的数量也不一定相同。