[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的情况,在实际编码过程中一定要注意这个问题。
- Golang简介
- 开发环境
- Golang安装
- 编辑器及快捷键
- vscode插件
- 第一个程序
- 基础数据类型
- 变量及匿名变量
- 常量与iota
- 整型与浮点型
- 复数与布尔值
- 字符串
- 运算符
- 算术运算符
- 关系运算符
- 逻辑运算符
- 位运算符
- 赋值运算符
- 流程控制语句
- 获取用户输入
- if分支语句
- for循环语句
- switch语句
- break_continue_goto语法
- 高阶数据类型
- pointer指针
- array数组
- slice切片
- slice切片扩展
- map映射
- 函数
- 函数定义和调用
- 函数参数
- 函数返回值
- 作用域
- 函数形参传递
- 匿名函数
- 高阶函数
- 闭包
- defer语句
- 内置函数
- fmt
- strconv
- strings
- time
- os
- io
- 文件操作
- 编码
- 字符与字节
- 字符串
- 读写文件
- 结构体
- 类型别名和自定义类型
- 结构体声明
- 结构体实例化
- 模拟构造函数
- 方法接收器
- 匿名字段
- 嵌套与继承
- 序列化
- 接口
- 接口类型
- 值接收者和指针接收者
- 类型与接口对应关系
- 空接口
- 接口值
- 类型断言
- 并发编程
- 基本概念
- goroutine
- channel
- select
- 并发安全
- 练习题
- 第三方库
- Survey
- cobra