概述
在go语言中,可以给任意自定义类型(包括内置类型,但不包括指针类型)添加相应的方法;
方法相关的特性如下:
1. 方法总是绑定对象实例,并隐式将实例作为第一实参(receiver)
2. 只能为当前包内命名类型定义方法
3. 参数receiver 可任意命名,如方法中为曾使用,可省略参数名
4. 参数receiver 类型可以是T or *T; 基类型T 不能是接口或指针
5. 不支持方法重载,receiver 只是参数签名的组成部分
6. 可用实例 value 或 pointer 调用全部方法,编译器自动转换
7. 没有构造和析构方法,通常用简单工厂模式返回对象实例
基础类型作为接收者
/*
1. 实现两数相加
1.1 函数方式
1.2 方法方式
*/
//1.1 函数方式,实现两数相加
func addFunc(n1, n2 int) int {
return n1 + n2
}
//1.2 方法方式,实现两数相加,首先定义一个类型 myInt
type myInt int
//为类型long 添加一个方法addMethod
func (n1 myInt) addMethod(n2 myInt) myInt {
return n1 + n2
}
func main() {
//1.1 函数实现
r1 := addFunc(1, 3)
fmt.Println("By function: ", r1)
//1.2 方法实现
var numOne myInt = 1
fmt.Println("By Method: ", numOne.addMethod(3))
}
结构体作为接收者
- 值语义
- 指针语义
//定义结构体Person
type Person struct {
name string
gender string //male or female
age int
}
//为Person 类定制一个结构化输出的方法, 类似java 中序列化方法 toString
func (p Person) toString() {
fmt.Printf("name: %s \n age: %d \n gender: %s \n", p.name, p.age, p.gender)
}
//为Person 添加一个 修改信息的方法
func (p *Person) modify(name, gender string, age int) {
p.name = name
p.age = age
p.gender = gender
}
//值语义 - 接收者 p 为普通变量,非指针变量
func (p Person) modifyValue(name, gender string, age int) {
p.name = name
p.age = age
p.gender = gender
fmt.Printf("************** modifyValue **************: \n")
p.toString()
}
func main() {
person := Person{
"Ryan",
"male",
26,
}
person.toString()
person.modify("Ryan.xu", "male", 27)
person.toString()
//通过值语义的方法来修改结构体成员,不能正常修改
person.modifyValue("go", "male", 8)
person.toString()
}
方法集
类型的变量能够调用哪些方法,这些方法的一个集合,简称“方法集”
1. 类型T 方法集包含全部receiver T 方法
2. 类型*T 方法集包含全部receiver T + *T 方法
3. 如类型S 包含匿名字段T,则S 方法集包含T 方法
4. 如类型S 包含匿名字段*T,则S 方法集包含T + *T 方法
5. 不管嵌入T 或者 *T, *S方法集总是包含 T + *T 方法
Tips: 用实例“普通对象”和“指针对象”调用方法(含匿名字段)不受方法集约束,编译器总是查找全部方法,并自动转换receiver 实参
匿名字段
- 方法继承
- 方法重写
方法继承
type Student struct {
Person //匿名字段, 引用前面的 Person类型,继承toString 的方法
id int
address string
}
func main() {
fmt.Println("************** 方法继承 **************")
stu := Student{Person{"Ryan.xu", "male", 26}, 10001, "SH"}
stu.toString()
}
方法重写
type Student struct {
Person //匿名字段
id int
address string
}
// student 重写 person 中的 toString 方法
func (s Student) toString() {
fmt.Printf("id: %d \n name: %s \n age: %d \n gender: %s \n address: %s \n",
s.id, s.name, s.age, s.gender, s.address)
}
func main() {
fmt.Println("************** 方法重写 **************")
stu := Student{Person{"Ryan.xu", "male", 26}, 10001, "SH"}
//就近原则,先找本作用域,找不到再用继承的方法
stu.toString()
//如果还想调用 Person 中的toString方法, 需显示调用
stu.Person.toString()
}