前言
本文将对方法进行介绍,方法的本质就是函数,介绍方法的同时也会顺带对比其与函数的不同之处。
方法
在 Go 中,我们可以为任何的数据类型定义方法(指针或接口除外),现在让我们看一看方法的声明和组成部分以及与函数有什么不同之处。
代码语言:go复制type Person struct {
age int
}
func (p *Person) SetAge(age int) error {
if age < 0 {
return errors.New("年龄不能小于 0 ")
}
p.age = age
return nil
}
上述代码定义了一个结构体 Person
,此结构体包含一个 age
属性,一个 SetAge
方法,此方法只作用于 Person
结构体。我们可以看到,该方法包含六部分,分别为:
- 1、关键字
声明方法时,必须以
func
关键字开头,还记得函数的声明吗,也是以这个关键字开头。 - 2、
receiver
部分(p *Person)
这部分,在Go
中称为receiver
部分,里面的参数称为receiver
参数,相比于函数,方法与其的声明区别就在于多了这一部分。 - 3、方法名。
Go
推荐使用驼峰命名的方式,和变量的命名规则一样,首字母大写的方法名可以在包外访问,小写的只能在包内访问。 - 4、参数列表 参数列表中声明了在方法体里所使用到的变量。参数列表位于方法名后面,用括号包裹着,多个参数使用逗号分隔开。
- 5、返回值列表 返回值为函数执行后的一个结果,上述代码只有一个返回值,如果有多个返回值,需要用括号包裹着,返回值之间用逗号分隔开。
- 6、方法体 大括号内就是方法体,存放着方法的具体实现。
方法的调用
通过 变量.方法名(参数)
的方式对方法进行调用。例如:
import (
"errors"
"fmt"
)
type Person struct {
age int
}
func (p *Person) SetAge(age int) error {
if age < 0 {
return errors.New("年龄不能小于 0 ")
}
p.age = age
return nil
}
func main() {
person := Person{}
err := person.SetAge(18)
if err != nil {
return
}
fmt.Println(person.age) // 18
}
创建一个 person
变量,然后调用 SetAge
函数。
Receiver 参数类型的选择
在 Receiver
部分,我们可以绑定值类型,也可以绑定指针类型,这两种类型什么时候使用呢?
- 如果方法体里不涉及到修改结构体变量的属性值,使用值类型
type Person struct {
age int
}
func (p Person) GetAge() int {
return p.age
}
对于 GetAge
方法,作用是返回年龄,没有涉及到修改年龄的操作,因此 receiver
部分,选择 Person
类型就可以。
- 如果方法体里有修改结构体变量的属性值的操作,使用指针类型
type Person struct {
age int
}
func (p *Person) SetAge(age int) error {
if age < 0 {
return errors.New("年龄不能小于 0 ")
}
p.age = age
return nil
}
SetAge
涉及到对结构体属性值修改的操作,因此 receiver
部分使用指针类型,通过指针,可以对所指向地址的变量进行修改操作。
方法的约束
Go
对方法声明的位置是有约束的,我们不能跨越包去声明一个类型的方法,根据这个特点我们可以发现:
- 不能为基本数据类型声明方法 因为基本数据类型所定义的位置,是不在我们所编码的包里面的。
- 不能跨越包为其他包的类型声明方法
这个是
Go
的所规定的的。小结本文介绍了 Go 方法的声明方式、组成部分和其与函数的不同点,同时指出Receiver
参数类型在不同场景下的选择,最后介绍了Go
对方法约束的体现。
我正在参与2023腾讯技术创作特训营第二期有奖征文,瓜分万元奖池和键盘手表