Go 语言方法
基本概念
Go 语言中方法(Methods)是定义在特定类型上的函数,类似于其他语言中类的方法,通过方法将函数与一个接收者(receiver)相关联,从而实现面向对象编程特性。
方法声明
方法在声明函数基础上多一个接收者参数:
func (receiver ReceiverType) MethodName(paramsList) ReturnType {
// 方法体
}
receiver
:接收者命名,通常采用接收者类型的第一个小写字母。一个方法只能有一个接收者,方法可以访问和修改接收者状态。ReceiverType
:接收者可以是除接口外任意类型。MethodName
:方法名。不同接收者可以具有同名方法。paramsList
:方法参数列表,可以没有参数。ReturnType
:方法返回类型,可以没有返回。
任何方法实际上都可以通过调整签名转为等价函数,即转移接收者作为其第一个参数:
package main
import "fmt"
// Rectangle 定义一个长方形结构体类型
type Rectangle struct {
width, height int
}
// Area 方法作用在 Rectangle 类型接收者上
func (r Rectangle) Area() int {
return r.width * r.height
}
// Area 函数和 Rectangle 类型上的 Area 方法等价
func Area(r Rectangle) int {
return r.width * r.height
}
func main() {
rect := Rectangle{width: 10, height: 5}
fmt.Println("方法调用: ", rect.Area())
fmt.Println("函数调用: ", Area(rect))
}
等价函数与类型之间虽然相互依赖,但没有直接绑定关系。方法绑定接收者后,能自动处理接收者指针与接收者值,调用方式保持一致:
package main
import "fmt"
type Rectangle struct{ width, height int }
// 方法绑定值接收者
func (r Rectangle) Area() int { return r.width * r.height }
// 方法绑定指针接收者
func (r *Rectangle) SetWidth(w int) { r.width = w }
func main() {
// 值接收方法调用
r := Rectangle{width: 10, height: 1}
rp := &Rectangle{width: 100, height: 1}
fmt.Println(r.Area(), rp.Area())
// 指针接收方法调用
r.SetWidth(20)
rp.SetWidth(200)
fmt.Println(r, rp)
}
方法继承
当使用嵌套结构体时,嵌入类型的方法可以直接被外层结构体调用。嵌入类型为匿名字段时,可以忽略字段名来调用内部类型方法,否则必须带上字段名:
package main
import "fmt"
// Shape 基本形状类型
type Shape struct {
ShapeType string
}
// Type 方法返回形状类型
func (s Shape) Type() string {
return s.ShapeType
}
// Circle 圆形,使用匿名字段继承 Shape
type Circle struct {
Shape
Radius float64
}
// Rectangle 矩形,使用具名字段继承 Shape
type Rectangle struct {
Shape Shape
Length float64
Width float64
}
func main() {
// 匿名字段的方法继承
circle := Circle{Shape{"Circle"}, 5}
fmt.Println(circle.Type()) // 直接调用内嵌类型的方法
fmt.Println(circle.Shape.Type()) // 也可以通过字段名调用
// 具名字段的方法继承
rectangle := Rectangle{Shape{"Rectangle"}, 4, 2}
fmt.Println(rectangle.Shape.Type()) // 调用时必须通过指定字段名
}
如果外部类型定义了与内部类型同名的方法,必须带上字段名来区分调用:
package main
import "fmt"
type Shape struct{ ShapeType string }
func (s Shape) Type() string { return "Shape: " + s.ShapeType }
// Circle 圆形,使用匿名字段继承 Shape
type Circle struct {
Shape
Radius float64
}
// Circle 拥有和内嵌匿名字段同名方法
func (c Circle) Type() string {
return "Circle with radius: " + fmt.Sprint(c.Radius)
}
func main() {
circle := Circle{Shape{"Circle"}, 5}
fmt.Println(circle.Type()) // 会调用 Circle 的 Type 方法
fmt.Println(circle.Shape.Type()) // 调用 Shape 的 Type 方法
}