法总是绑定对象实例,并隐式将实例作为第⼀实参 (receiver)。
• 只能为当前包内命名类型定义⽅法。
• 参数 receiver 可任意命名。如⽅法中未曾使⽤,可省略参数名。
• 参数 receiver 类型可以是 T 或 *T。基类型 T 不能是接⼝或指针。
• 不⽀持⽅法重载, receiver 只是参数签名的组成部分。
• 可⽤实例 value 或 pointer 调⽤全部⽅法,编译器⾃动转换。
• Go 不允许同名函数,但是同名方法可以定义在不同的类型上
• method和receiver必须在同一个包里定义
• 作为函数参数,值类型就是值类型,指针类型就是指针类型
• 方法有一个值类型和指针类型的接受者时,都可以直接调用,内部会
自动进行语法的转换。
一个方法只是一个函数,它有一个特殊的接收者(receiver)类型,该接收者放在 func 关键字和函数名之间。接收者可以是结构体类型或非结构体类型。可以在方法内部访问接收者。
一般语法为:
func (t receiver_type) methodName(parameter list) {}
一、参数 receiver 类型可以是 T 或 *T。以指针为接收者也是可以的。
两者的区别在于, 以*T为接收者时,方法内部对其的修改对于外部有效,而以 T作为接受者时,对于外部无效。
1func (e Employee) changeName(newName string) {
2 e.name = newName
3}
4func (e *Employee) changeAge(newAge int) {
5 e.age = newAge
6}
7 emp1 := Employee{
8 name: "张三",
9 salary: 6000,
10 currency: "$",
11 age: 18,
12 Address: Address{"山东", "济南"},
13 }
14 emp1.displaySalary()
15
16 fmt.Println("Before call changeName ", emp1.name)
17 //修改名字,未发生变化因为是值传递
18 emp1.changeName("zhangsan")
19 fmt.Println("After call changeName ", emp1.name) //After call changeName 张三
20
21 fmt.Println("Before change age", emp1.age)
22 //利用指针来修改年龄
23 emp1.changeAge(50)
24 fmt.Println("After change age", emp1.age) //After change age 50
二、Go 不允许同名函数,但是同名方法可以定义在不同的类型上
1//Rectangle 代码规范
2type Rectangle struct {
3 width float32
4 height float32
5}
6//Circle 代码规范
7type Circle struct {
8 radius float32
9}
10func (e Employee) changeName(newName string) {
11 e.name = newName
12}
13func (e *Employee) changeAge(newAge int) {
14 e.age = newAge
15}
16func main() {
17 //计算面积
18 re := Rectangle{20, 30}
19 c := Circle{40}
20 //两个类型调用同名方法
21 fmt.Println(re.getArea())
22 fmt.Println(c.getArea())
23}
1emp1 := Employee{
2 name: "张三",
3 salary: 6000,
4 currency: "$",
5 age: 18,
6 Address: Address{"山东", "济南"},
7 }
8 //提阶
9 emp1.fullAddress() //山东 济南,提阶相当于直接访问Address里的
10 emp1.Address.fullAddress() //山东 济南
四、非结构类型的方法
非结构体类型也可以定义方法,不过这里需要注意一点。为了定义某个类型的方法,接收者类型的定义与方法的定义必须在同一个包中。
因为必须在一个包中而int则在main包中我们没法去定义这个里为了简单直观,给int声明了别名
1//非结构体方法扩展
2type myInt int
3
4func (a myInt) add(b myInt) myInt {
5 return a + b
6}
7func main() {
8 //调用扩展的方法
9 num1 := myInt(5)
10 num2 := myInt(10)
11 sum := num1.add(num2)
12 fmt.Println("Sum is", sum)
13
14}
下面附上完整实例程序
1package main
2
3import (
4 "fmt"
5 "math"
6)
7
8//Employee 需要添加注释或者改成非导出变量(首字母小写)
9type Employee struct {
10 name string
11 currency string
12 salary int
13 age int
14 Address
15}
16
17//Address 代码规范
18type Address struct {
19 city string
20 state string
21}
22
23//Rectangle 代码规范
24type Rectangle struct {
25 width float32
26 height float32
27}
28
29//Circle 代码规范
30type Circle struct {
31 radius float32
32}
33
34//Employee 的方法
35func (e Employee) displaySalary() {
36 fmt.Println(e)
37}
38func (e Employee) changeName(newName string) {
39 e.name = newName
40}
41func (e *Employee) changeAge(newAge int) {
42 e.age = newAge
43}
44
45//Address 的方法
46func (add Address) fullAddress() {
47 fmt.Println(add.city, add.state)
48}
49
50//Rectangle 的方法计算面积
51func (r Rectangle) getArea() float32 {
52 return r.width * r.height
53}
54
55//Circle 的方法
56func (c Circle) getArea() float32 {
57 return math.Pi * c.radius * c.radius
58}
59
60//非结构体方法扩展
61type myInt int
62
63func (a myInt) add(b myInt) myInt {
64 return a + b
65}
66func main() {
67 //调用方法
68 emp1 := Employee{
69 name: "张三",
70 salary: 6000,
71 currency: "$",
72 age: 18,
73 Address: Address{"山东", "济南"},
74 }
75 emp1.displaySalary()
76
77 fmt.Println("Before call changeName ", emp1.name)
78 //修改名字,未发生变化因为是值传递
79 emp1.changeName("zhangsan")
80 fmt.Println("After call changeName ", emp1.name) //After call changeName 张三
81
82 fmt.Println("Before change age", emp1.age)
83 //利用指针来修改年龄
84 emp1.changeAge(50)
85 fmt.Println("After change age", emp1.age) //After change age 50
86
87 //提阶
88 emp1.fullAddress() //山东 济南,提阶相当于直接访问Address里的
89 emp1.Address.fullAddress() //山东 济南
90
91 //计算面积
92 re := Rectangle{20, 30}
93 c := Circle{40}
94 //两个类型调用同名方法
95 fmt.Println(re.getArea())
96 fmt.Println(c.getArea())
97
98 //调用扩展的方法
99 num1 := myInt(5)
100 num2 := myInt(10)
101 sum := num1.add(num2)
102 fmt.Println("Sum is", sum)
103
104}
原文发布时间为:2018-12-12
本文作者:Golang语言社区
本文来自云栖社区合作伙伴“ Golang语言社区”,了解相关信息可以关注“Golangweb”微信公众号