在Go语言中没有类,但是,是有方法的。
给结构体定义方法,在对应的func和方法名之间,加上方法的接收者就可以了。

定义一个结构体

  1. type Vertex struct {
  2. X, Y float64
  3. }

希望Vertex有一个abs()方法,就这样写

  1. func (v *Vertex) Abs() float64 {
  2. return math.Sqrt(v.X * v.X + v.Y * v.Y)
  3. }

注意结构体的方法接收者是指针时,调用需要在前面加上&符号。

  1. (&Vertex{3, 4}).Abs()

这样写有点冗长,在结构的方法有多个的时候,调用也不方便。你可以初始化一个变量,然后再调用。

  1. v := &Vertex{3, 4}
  2. v.Abs()

完整代码

  1. package main
  2. import(
  3. "fmt"
  4. "math"
  5. )
  6. type Vertex struct {
  7. X, Y float64
  8. }
  9. func (v *Vertex) Abs() float64 {
  10. return math.Sqrt(v.X * v.X + v.Y * v.Y)
  11. }
  12. func main() {
  13. v := &Vertex{3, 4}
  14. fmt.Println(v.Abs())
  15. }

除了结构体,还可以对自己包中的任意类型,定义任意方法。(对来自其他包的类型或基础类型是不能定义方法的)。

比如,可以创建一个类型

  1. type MyFloat float64

然后给这个 MyFloat 定义方法

  1. func (f MyFloat) Abs() float64 {
  2. if f < 0 {
  3. return float64(-f)
  4. }
  5. return float64(f)
  6. }

完整示例

  1. package main
  2. import ("fmt"
  3. "math"
  4. )
  5. type MyFloat float64
  6. func (f MyFloat) Abs() float64 {
  7. if f < 0 {
  8. return float64(-f)
  9. }
  10. return float64(f)
  11. }
  12. func main() {
  13. f := MyFloat(-math.Sqrt2)
  14. fmt.Println(f.Abs())
  15. }

上面两个例子中,分别实现了两个Abs()。一个指针类型,一个值类型。

  1. 使用指针是为了避免在每个方法调用时都进行值拷贝(如果类型是大型结构体的话,会有效率问题);其次,指针方法可以修改接收者指向的值。
  2. 我们定义一个Scale方法,用指针类型做接收者。会发现Scale之后,Vertex的值发生了改变,并影响以后的运算结果。
  1. package main
  2. import(
  3. "fmt"
  4. "math"
  5. )
  6. type Vertex struct {
  7. X, Y float64
  8. }
  9. func (v *Vertex) Scale(f float64) {
  10. v.X = v.X * f
  11. v.Y = v.Y * f
  12. }
  13. func (v Vertex) Abs() float64 {
  14. return math.Sqrt(v.X * v.X + v.Y * v.Y)
  15. }
  16. func main() {
  17. v := Vertex{3, 4}
  18. fmt.Printf("Before scaling: %+v, ABS: %v\n", v, v.Abs())
  19. v.Scale(5)
  20. fmt.Printf("After scaling: %+v, ABS: %v\n", v, v.Abs())
  21. }

运行结果

  1. Before scaling: {X:3 Y:4}, ABS: 5
  2. After scaling: {X:15 Y:20}, ABS: 25

Go 方法method - 图1