-
Notifications
You must be signed in to change notification settings - Fork 2
Open
Labels
Description
方法和接收者
方法的声明
方法声明和函数声明只有一点差别,只是在关键字func和方法名之间多加了一个参数。这个参数把这个方法绑定到这个参数对应的类型上。
类型拥有的所有方法名都必须是唯一的,因为每一个类型都有它自己的命名空间,所以不同类型可以使用相同的方法名。
方法的接收者
以下方法声明里的参数 t 就是这个方法的接收者
func (t *Type) Method() {} // pointer receiverfunc (t Type) Method() {} // value receiverpointer receiver
指针接收者,接收者的类型是一个指针,是接收者的引用,对这个引用的修改之间影响真正的接收者
value receiver
值接收者,接收者的类型是一个值,传递给方法的实际上是值的一个副本,方法内部无法对其真正的接收者做更改
使用时存在两种隐式转换
指针方法和值方法都可以在指针或非指针上被调用
-
值类型的接收者也可以使用指针类型的调用(实参接收者是 *T 类型的变量,而形参接收者是 T 类型,编译器会隐式的解引用接收者,获取实际的取值 )
a.printName() // 隐式转换为(*a)
-
指针类型的接收者也可以使用值类型的调用(实参接收者是 T 类型的变量,而形参接收者是 *T 类型,编译器会隐式的获取变量的地址)
f.setName("Fred1") // 隐式转换为(&f)
示例代码
// 这个 `person` 结构体有两个字段
type Person struct {
name string
age int
}
// 定义普通函数
func printName(name string) {
fmt.Printf("Name is %s \n", name)
}
// 定义 Person 类型的方法(函数名前面多加了一个参数, 这个 p 是这个方法的接收者)
// 定义值接收者
func (p Person) printName() {
fmt.Printf("Name is %s \n", p.name)
}
// 定义指针接收者
func (p *Person) setName(name string) {
p.name = name
}a := &Person{name: "Ann", age: 40}
a.setName("Ann1")
// 值类型的接收者也可以使用指针类型的调用
a.printName() // 隐式转换为(*a)
// 实际上编译器,已经对该类型进行了如下转换
(*a).printName()f := Person{name: "Fred", age: 30}
// 虽然 setName 这个方法要求接收者是一个指针,但我们可以使用简写
// 实际上编译器会对变量进行 &f 的隐式转换(只允许变量)
f.setName("Fred1") // 隐式转换为(&f)
(&f).setName("Fred2")
f.printName() 在定义方法接收者时,应该使用指针接收者还是值接收者?
什么时候该使用 pointer receiver
- 如果想在方法中改变接收者的状态,操作它的值,使用指针接收器。
- 效率:如果实参定义的 struct 很大,避免复制整个实参。
- 一致性:习惯上遵循如果 Struct 的任何一个方法使用了指针接收者,那么所有的 struct 方法都应该使用指针接收者,即使有些方法并不一定需要。
什么时候使用 value receiver
- 如果不需要编辑接收者的值