方法定义:专门给某一类型定义的函数。
我们可以给任何自定义类型添加一个或多个方法,每种类型对应的方法必须和类型定义在同一个包中。因此是无法给int这类内置类型添加方法的。所有给定类型的方法属于该类型的方法集。
方法用法如下:
package main
import "fmt"
type Student struct {
name string
age int
grade int
}
// 给Student类型定义study方法
func (stu Student) study (book string) {
fmt.Println(stu.name, "学习了:", book)
}
func main() {
var xiaoming = Student{
name: "xiaoming",
age : 18,
grade: 22,
}
//直接调用
xiaoming.study("go语言")//xiaoming 学习了: go语言
//方法表达式调用 把方法绑定到类型上面 类型对象可以直接做第一个参数
var study = Student.study
study(xiaoming, "mysql应用")//xiaoming 学习了: mysql应用
//方法值调用 把方法绑定到对象上
var xiaomingStudy = xiaoming.study
xiaomingStudy("数据结构")//xiaoming 学习了: 数据结构
}
上例也能看到方法表达式和方法值的用法。方法表达式的特性可以将方法还原为普通类型的函数,方法值表示方法已经绑定到了对象上,不用再另外传对象参数。
普通函数与方法的区别
1.对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然。
2.对于方法,接收者为值类型时,可以直接用指针类型的变量调用方法,反过来同样也可以。
package main
import "fmt"
type Student struct {
name string
age int
grade int
}
// 给Student类型定义study方法
func (stu Student) study (book string) {
fmt.Println(stu.name, "学习了:", book)
}
func (stu *Student) play (game string) {
fmt.Println(stu.name, "玩耍了:", game)
}
func main() {
var xiaoming = Student{
name: "xiaoming",
age : 18,
grade: 22,
}
var xiaohuaP = &Student{
name: "xiaohua",
age : 18,
grade: 22,
}
xiaoming.study("go语言")//xiaoming 学习了: go语言
xiaohuaP.study("mysql")//xiaohua 学习了: mysql
xiaoming.play("王者荣耀")//xiaoming 玩耍了: 王者荣耀
xiaohuaP.play("英雄联盟")//xiaohua 玩耍了: 英雄联盟
}
方法集
• 类型 T 方法集包含全部 receiver T 方法。
• 类型 *T 方法集包含全部 receiver T + *T 方法。
上面的含义解析如下:
- 一个变量a,类型是T,不是指针。那a能调用的方法有接收者为T类型的方法,不能调用接收者为*T类型的方法。
- 一个变量b,类型是*T,是指针。那b不仅能调用接收者为*T类型的方法,也能调用接收者为T的方法。
- 一个方法,接收者为T类型,那变量a和b都能调用它。
- 一个方法,接收者为*T类型,那只有变量b(指针能调用它)。
上面的例子能运行是因为go会帮我们做隐式取值操作。比如像下面就会有一些会编译错误。
(Student{"1", 1, 2}).study("go语言")//xiaoming 学习了: go语言
(&Student{"1", 1, 2}).study("mysql")//xiaohua 学习了: mysql
(&Student{"1", 1, 2}).play("王者荣耀")//xiaoming 玩耍了: 王者荣耀
//(Student{"1", 1, 2}).play("英雄联盟")//xiaohua 玩耍了: 英雄联盟
最后一行会编译不过,因为类型T变量不包含receiver为*T的方法,所以不能调用play。