方法
方法能给用户定义的类型添加新的行为。方法实际上也是函数,只是在声明时,在关键字func 和方法名之间增加了一个参数,可以参考如下示例:
// 这个示例程序展示如何声明
// 并使用方法
package main
import (
"fmt"
)
// user在程序里定义一个用户类型
type user struct {
name string
email string
}
// notify使用值接收者实现了一个方法
func (u user) notify() {
fmt.Printf("Sending User Email To %s<%s>\n", u.name,
u.email)
}
// changeEmail使用指针接收者实现了一个方法,可以修改原数据
func (u *user) changeEmail(email string) {
u.email = email
}
// changeName使用值接收者实现了一个方法,由于user是结构体,属于值类型,因此无法修改原数据
func (u user) changeName(name string) {
u.name=name
}
func main() {
// user类型的值可以用来调用
// 使用值接收者声明的方法
bill := user{"Bill", "bill@email.com"}
bill.notify()
// 指向 user 类型值的指针也可以用来调用
// 使用值接收者声明的方法
lisa := &user{"Lisa", "lisa@email.com"}
lisa.notify()
// user类型的值也可以用来调用
// 使用指针接收者声明的方法
// 实际上:Go编译器为了支持这种方法调用将bill.changeEmail("bill@newdomain.com")转为(&bill).changeEmail ("bill@newdomain.com")
// 由于是指针,所以可以实现修改原数据
bill.changeEmail("bill@newdomain.com")
bill.notify()
// 指向 user 类型值的指针可以用来调用
// 使用指针接收者声明的方法
// 实际上:Go编译器为了支持这种方法调用,指针被解引用为值,lisa.notify()转为(*lisa).notify()
lisa.changeEmail("lisa@newdomain.com")
lisa.notify()
//分析同上,
bill.changeName("david")
bill.notify()
lisa.changeName("lucy")
lisa.notify()
}
//输出:
Sending User Email To Bill<bill@email.com>
Sending User Email To Lisa<lisa@email.com>
Sending User Email To Bill<bill@newdomain.com>
Sending User Email To Lisa<lisa@newdomain.com>
Sending User Email To Bill<bill@newdomain.com>
Sending User Email To Lisa<lisa@newdomain.com>
关键字 func 和函数名之间的参数被称作接收者,将函数与接收者的类型绑在一起。如果一个函数有接收者,这个函数就被称为方法
使用值接收者还是指针接收者
是使用值接收者还是指针接收者,不应该由该方法是否修改了接收到的值来决定。这个决策 应该基于该类型的本质。这条规则的一个例外是,需要让类型值符合某个接口的时候,即便类型的本质是非原始本质的,也可以选择使用值接收者声明方法。这样做完全符合接口值调用方法的机制
接口
接口是用来定义行为的类型。这些被定义的行为不由接口直接实现,而是通过方法由用户 定义的类型实现。如果用户定义的类型实现了某个接口类型声明的一组方法,那么这个用户定 义的类型的值就可以赋给这个接口类型的值。这个赋值会把用户定义的类型的值存入接口类型 的值。
对接口值方法的调用会执行接口值里存储的用户定义的类型的值对应的方法。因为任何用户 定义的类型都可以实现任何接口,所以对接口值方法的调用自然就是一种多态。在这个关系里, 用户定义的类型通常叫作实体类型,原因是如果离开内部存储的用户定义的类型的值的实现,接口值并没有具体的行为
实体值赋值后接口值
实体指针赋值后接口值
方法集
如果使用指针接收者来实现一个接口,那么只有指向那个类型的指针才能够实现对应的接口。如果使用值接收者来实现一个接口,那么那个类型的值和指针都能够实现对应的接口
方法集规则
网友评论