定义

在 Go 语言中,结构体就像是类的一种简化形式,传统面向对象语言中类有属性,同时也有方法。同样 Go 语言中也有方法 method 的概念。它实际上也是函数,只是在声明时,在关键字 func 和函数名之间增加了一个作为接受者(receiver)的参数,通俗的说方法就是带有接收者的函数。

  1. func (r ReceiverType) funcName(parameters) (results)

注意接受者不一定是结构体,可以使用户定义的其他类型。

现在假设有这么一个场景,你定义了一个长方形 Rectangle 结构体,你现在想要计算它的面积,那么按照我们一般的思路应该会用下面的方式来实现。

  1. package main
  2. import "fmt"
  3. type Rectangle struct {
  4. width, height float64
  5. }
  6. func area(r Rectangle) float64 {
  7. return r.width * r.height
  8. }
  9. func main() {
  10. r1 := Rectangle{12, 2}
  11. r2 := Rectangle{9, 4}
  12. fmt.Println("Area of r1 is: ", area(r1))
  13. fmt.Println("Area of r2 is: ", area(r2))
  14. }

这段代码可以计算出来长方形的面积,但是 area() 不是作为 Rectangle 的方法实现的(类似面向对象里面的方法),而是将 Rectangle 的对象(如 r1 , r2 )作为参数传入函数计算面积的。

这样实现当然没有问题,但是当需要增加圆形、正方形、五边形甚至其它多边形的时候,你想计算他们的面积的时候怎么办啊?那就只能增加新的函数!但是函数名你就必须要跟着换了,变成 area_rectangle , area_circle , area_triangle

很显然,这样的实现并不优雅,并且从概念上来说“面积”是“形状”的一个属性,它是属于这个特定的形状的,就像长方形的长和宽一样。这是 method 就排上了用场。下面我们将开始的例子用 method 来实现:

  1. package main
  2. import (
  3. "fmt"
  4. "math"
  5. )
  6. type Rectangle struct {
  7. width, height float64
  8. }
  9. type Circle struct {
  10. radius float64
  11. }
  12. func (r Rectangle) area() float64 {
  13. return r.width * r.height
  14. }
  15. func (c Circle) area() float64 {
  16. return c.radius * c.radius * math.Pi
  17. }
  18. func main() {
  19. r1 := Rectangle{12, 2}
  20. r2 := Rectangle{9, 4}
  21. c1 := Circle{10}
  22. c2 := Circle{25}
  23. fmt.Println("Area of r1 is: ", r1.area())
  24. fmt.Println("Area of r2 is: ", r2.area())
  25. fmt.Println("Area of c1 is: ", c1.area())
  26. fmt.Println("Area of c2 is: ", c2.area())
  27. }

在使用 method 的时候重要注意几点:

  • 虽然 method 的名字一模一样,但是如果接收者不一样,那么 method 就不一样;
  • method 里面可以访问接收者的字段;
  • 调用 method 通过 . 访问,就像 struct 里面访问字段一样。

同时再次强调 method 并不是只能作用在 struct 上面,它可以定义在任何你自定义的类型、内置类型、 struct 等各种类型上面。

指针或值作为接收者