go-方法

87 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情

方法

go没有类。不过你可以为结构体类型定义方法。方法就是一类带特殊的 接收者 参数的函数。方法接收者在它自己的参数列表内,位于func关键字和方法名之间。

package main

import (
   "fmt"
   "math"
)

type Vertex struct {
   X, Y float64
}

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

func main() {
   v := Vertex{3, 4}
   fmt.Println((v).Abs())
}

方法即函数

方法只是个带接收者参数的函数。 可以和普通的函数对比下:

package main

import (
   "fmt"
   "math"
)

type Vertex struct {
   X, Y float64
}

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

func main() {
   v := Vertex{3, 4}
   fmt.Println(Abs(v))
}

功能上没啥区别。

非结构体类型申明方法

你只能为同一包内定义的类型的接收者声明方法,而不能为其他包内定义的类型(包括int之类的内建类型)的接收者声明方法。

package main

import (
   "fmt"
   "math"
)

type MyFloat float64

func (f MyFloat) Abs() float64 {
   if f < 0 {
      return float64(-f)
   }

   return float64(f)
}

func main() {
   f := MyFloat(-math.Sqrt2)
   fmt.Println(f.Abs())
}

方法-指针接收者

你可以为指针接收者声明方法。这意味着对于某类型T,接收者的类型可以用*T的文法。

指针接收者的方法可以修改接收者指向的值。若使用值接收者,那么会对原始值的副本进行操作。

package main

import (
   "fmt"
   "math"
)

type Vertex1 struct {
   X, Y float64
}

func (v Vertex1) Abs() float64 {
   return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func (v *Vertex1) Scale(f float64) {
   v.X = v.X * f
   v.Y = v.Y * f
}

func main() {
   v := Vertex1{3, 4}
   v.Scale(10)
   fmt.Println(v.Abs())
}

其中v.Scale(10)本质上是(&v).Scale(10)相当于go的语法糖。

&表示取地址,*表示解析地址

改写成函数

把接收者移到方法入参列表内,实现功能一样。

package main

import (
   "fmt"
   "math"
)

type Vertex1 struct {
   X, Y float64
}

func Abs(v Vertex1) float64 {
   return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func Scale(v *Vertex1, f float64) {
   v.X = v.X * f
   v.Y = v.Y * f
}

func main() {
   v := Vertex1{3, 4}
   Scale(&v, 10)
   fmt.Println(Abs(v))
}