多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] Go语言中的方法(Method)是一种作用于特定类型变量的函数。这种特定类型变量叫做接收者(Receiver)。接收者的概念就类似于 Python 中的 self 。 方法的定义格式如下: ```go func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) { 函数体 } ``` >[info] 说明: > 1. 接收者变量:接收者中的参数变量名在命名时,官方建议使用接收者类型名称首字母的小写,而不是self、this之类的命名。例如,Student 类型的接收者变量应该命名为 S。 > 2. 接收者类型:接收者类型和参数类似,可以是指针类型和非指针类型。 > 3. 方法名、参数列表、返回参数:具体格式与函数定义相同。 ## 值类型的接收者 当方法作用于值类型接收者时,Go语言会在代码运行时将接收者的值复制一份。在值类型接收者的方法中可以获取接收者的成员值,但修改操作只是针对副本,无法修改接收者变量本身。 ```go package main import "fmt" // Person 是人的结构体 type Person struct { name string age int8 } // NewPerson 是 Person 结构体的构造函数 func NewPerson(name string, age int8) *Person { return &Person{name: name, age: age} } // Dream 是 Person 结构体的梦想方法 func (p Person) Dream(dream string) { fmt.Printf("%s 的梦想是%s\n", p.name, dream) } func main() { // 构造结构体 p1 := NewPerson("jiaxzeng", 18) // 调用Person的Dream的方法 p1.Dream("成为大富翁") p2 := NewPerson("jiaxzeng", 18) p2.SetAge() fmt.Printf("p2.age: %v\n", p2.age) } // 运行结果 // jiaxzeng 的梦想是成为大富翁 ``` ## 指针类型的接收者 指针类型的接收者由一个结构体的指针组成,由于指针的特性,调用方法时修改接收者指针的任意成员变量,在方法结束后,修改都是有效的。 ```go package main import "fmt" // Person 是人的结构体 type Person struct { name string age int8 } // NewPerson 是 Person 结构体的构造函数 func NewPerson(name string, age int8) *Person { return &Person{name: name, age: age} } // SetAge 是 Person 结构体的修改年龄方法 func (p *Person) SetAge() { p.age++ } func main() { // 构造结构体 p2 := NewPerson("jiaxzeng", 18) fmt.Printf("p2.age: %v\n", p2.age) // 调用Person的SetAge的方法 p2.SetAge() fmt.Printf("p2.age: %v\n", p2.age) } // 运行结果 // p2.age: 18 // p2.age: 19 ``` ## 指针类型接收者使用场景 1. 需要修改接收者中的值 2. 接收者是拷贝代价比较大的大对象 3. 保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者。 ## 注意事项 因为slice和map这两种数据类型都包含了指向底层数据的指针,因此我们在需要复制它们时要特别注意。我们来看下面的例子: ```go // Person 是人的结构体 type Person struct { name string age int8 dreams []string } // NewPerson 是 Person 结构体的构造函数 func NewPerson(name string, age int8) *Person { return &Person{name: name, age: age} } // SetDream 是修改 Person 结构体的梦想方法 func (p *Person) SetDream(dreams []string) { p.dreams = dreams } // SetAge 是 Person 结构体的修改年龄方法 func (p *Person) SetAge() { p.age++ } func main() { p1 := NewPerson("jiaxzeng", 18) dreams := []string{"吃饭", "睡觉"} p1.SetDream(dreams) fmt.Printf("p1: %v\n", p1) dreams[1] = "玩耍" fmt.Printf("p1: %v\n", p1) } // 运行结果 // p1: &{jiaxzeng 18 [吃饭 睡觉]} // p1: &{jiaxzeng 18 [吃饭 玩耍]} ``` >[danger] 上面的允许结果,修改 dreams 变量的值影响到结构体的值。这个是不允许出现的情况。原因是处在切片是引用类型,结构体方法传递的是变量指针。 应该使用以下方式设置。copy函数是返回一个新的切片,所以修改原来的切片不影响结构体。 ```go func (p *Person) SetDream(dreams []string) { // p.dreams = dreams p.dreams = make([]string, len(dreams)) copy(p.dreams, dreams) } ``` >[info] 同样的问题也存在于返回值slice和map的情况,在实际编码过程中一定要注意这个问题。