Go中方法是作用在指定的数据类型上的,即必须和指定的数据类型绑定,因此自定义类型都可以具有方法,而不仅仅是结构体。
方法声明与调用
方法的定义
func (receiver type) methodName (argument_list) (return_value_list) {
// method body
return value
}
元素 | 描述 |
---|---|
argument_list | 参数列表,表示方法的输入。 |
receiver type | 表示方法和指定的type 类型进行绑定,该方法作用于type 类型。type 可以是结构体也可以是自定义类型。 |
receiver | 是type 类似的一个实例变量 |
return_value_list | 返回值列表,表示返回的值,可以为多个。 |
method_body | 方法体,为实现某功能的代码块。 |
return |
return 语句不是必须的 |
type User struct {
Id int
}
// 为User类型绑定TableName方法
func (t User) TableName() string {
fmt.Printf("%+v\n", t)
return "users"
}
func main() {
u := User{1}
name := u.TableName()
fmt.Println(name)
}
语法说明
-
func (t User) TableName(){}
表示User
类型具有一个方法,方法名称为TableName
。 -
(t User)
体现了TableName
方法是和User
类型绑定的 -
TableName()
方法只能通过User
类型的变量来调用,而不能直接调用,也不能使用其它类型变量来调用。 -
(t User)
中的t
变量表示哪个User
变量调用,这个t
就是它的副本,类似函数传参。 - 若需要传入引用类型而不采用副本的方式可使用
(t *User)
的方式 -
t
这个名字由开发人员自行指定,不是固定的。
方法的调用和传参机制
方法的调用和传参机制和函数基本一致,不同之处在于方法调用时会将调用方法的变量作为实参也传递给方法,若变量是值类型则进行值拷贝,若变量是引用类型,则进行地址拷贝。
type Circle struct {
radius float64
}
func (t Circle) area() float64 {
return 3.14 * t.radius * t.radius
}
func main() {
var c Circle
c.radius = 4.0
res := c.area()
fmt.Println(res) // 50.24
}
由于采用值拷贝的方式效率较低,建议采用传递指针的方式以提升效率。
注意事项
- 结构体类型是值类型,方法调用中遵守值类型的传递机制,即值类型采用的是值拷贝传递的方式。
- 若希望在方法中修改结构体变量的值可通过结构体指针的方式来处理
- Go中方法的作用是在指定的数据类型上(和指定的数据类型绑定),因此自定义类型都可以有方法,而不仅仅是结构体,基本类型也可以拥有方法。
- 方法的访问范围控制的规则和函数一样,方法名首字母小写只能在本包访问,首字母大写可以在本包和其它包访问。
- 若某个变量实现了
String()
方法则fmt.Println()
默认会调用此变量的String()
方法进行输出。
type User struct {
Id int
Name string
}
func (t *User) String() string {
str := fmt.Sprintf("id:%d, name:%s\n", t.Id, t.Name)
return str
}
func main() {
u := User{1, "alice"}
fmt.Println(&u)
}
方法与函数
方法和函数的区别
区别 | 函数 | 方法 |
---|---|---|
调用方式 | 函数名(实参列表) | 变量.方法名(实参列表) |
接收值类型时 | 不能将指针类型的数据直接传递 | 可直接使用指针类型的变量调用方法 |
type User struct {
Id int
Name string
}
func (t *User) Print() {
fmt.Printf("id:%d, name:%s\n", t.Id, t.Name)
}
func main() {
u := User{1, "alice"}
u.Print()
(&u).Print()
}
注意:从形式上看(&u)
是传入地址,但本质仍然是值拷贝。
type User struct {
Id int
Name string
}
func (t User) Print() {
t.Id = 2
fmt.Printf("id:%d, name:%s\n", t.Id, t.Name)
}
func main() {
u := User{1, "alice"}
u.Print() // id:2, name:alice
(&u).Print() // id:2, name:alice
fmt.Printf("id:%d, name:%s\n", u.Id, u.Name) // id:1, name:alice
}