# Golang 方法
Go 语言中同时有函数和方法。一个方法就是一个包含了 接受者 的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针。
所有给定类型的方法属于该类型的方法集。
方法只是一个函数,它带有一个特殊的接收器类型,它是在 func 关键字和方法名之间编写的。接收器可以是 struct 类型或非 struct 类型。接收方可以在方法内部访问。
方法能给用户自定义的类型添加新的行为。它和函数的区别在于方法有一个接收者,给一个函数添加一个接收者,那么它就变成了方法。接收者可以是值接收者,也可以是指针接收者。
在调用方法的时候
- 值类型既可以调用值接收者的方法,也可以调用指针接收者的方法
- 指针类型既可以调用指针接收者的方法,也可以调用值接收者的方法。
也就是说,不管方法的接收者是什么类型,该类型的值和指针都可以调用,不必严格符合接收者的类型。
# 一、Golang 方法声明
基本语法:
// 方法
func (t Type) methodName(parameter list)(return list) {
}
// 函数
func funcName(parameter list)(return list){
}
示例:
package main
import (
"fmt"
)
type Employee struct {
name string
salary int
currency string
}
/*
displaySalary 是 Employee 类型的一个方法
*/
func (e Employee) displaySalary() {
// 方法内部可以访问接收者
fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)
}
func main() {
emp1 := Employee {
name: "Sam Adolf",
salary: 5000,
currency: "$",
}
emp1.displaySalary() // 可以通过 Employe 类型的示例来调用 displaySalary
}
不同类型的接收者可以有 相同 的方法名:
package main
import (
"fmt"
"math"
)
type Rectangle struct {
width, height float64
}
type Circle struct {
radius float64
}
func (r Rectangle) area() float64 {
return r.width * r.height
}
//该 method 属于 Circle 类型对象中的方法
func (c Circle) area() float64 {
return c.radius * c.radius * math.Pi
}
func main() {
r1 := Rectangle{12, 2}
r2 := Rectangle{9, 4}
c1 := Circle{10}
c2 := Circle{25}
fmt.Println("Area of r1 is: ", r1.area())
fmt.Println("Area of r2 is: ", r2.area())
fmt.Println("Area of c1 is: ", c1.area())
fmt.Println("Area of c2 is: ", c2.area())
}
输出:
Area of r1 is: 24
Area of r2 is: 36
Area of c1 is: 314.1592653589793
Area of c2 is: 1963.4954084936207
- 虽然 method 的名字一模一样,但是如果接收者不一样,那么 method 就不一样
- method 里面可以访问接收者的字段
- 调用 method 通过 . 访问,就像 struct 里面访问字段一样
# 二、Golang 方法继承
Golang 中 method 是可以“继承”的,这里的继承跟 Java 中的那种 extends 的继承不是一回事,而是说,如果匿名字段实现了一个 method,那么包含这个匿名字段的 struct 也能调用该 method。
# 1. 方法继承
下面代码定义了三个结构体:
- Human
- Student
- Employee
Student 和 Employee 中都有一个 Human 类型的匿名字段。
package main
import "fmt"
type Human struct {
name string
age int
phone string
}
type Student struct {
Human //匿名字段
school string
}
type Employee struct {
Human //匿名字段
company string
}
// Human 类型定义的方法
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
func main() {
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
// 包含匿名字段的结构体也可以调用匿名字段拥有的方法
mark.SayHi()
sam.SayHi()
}
输出:
Hi, I am Mark you can call me on 222-222-YYYY
Hi, I am Sam you can call me on 111-888-XXXXCOPY
# 2. 方法重写
如果包含匿名字段的类型有用跟匿名字段拥有的方法的名称重复了,那么就覆盖了,
package main
import "fmt"
type Human struct {
name string
age int
phone string
}
type Student struct {
Human //匿名字段
school string
}
type Employee struct {
Human //匿名字段
company string
}
// Human 定义 method
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
// Employee 的 method 重写 Human 的 method
func (e *Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone)
}
func main() {
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
mark.SayHi()
sam.SayHi()
}
输出:
Hi, I am Mark you can call me on 222-222-YYYY
Hi, I am Sam, I work at Golang Inc. Call me on 111-888-XXXX
可以看到由于 Employee 类型重写了 SayHi 方法,所以调用的是 Employee 类型定义的 SayHi 方法。