方法
方法的声明: 在函数声明时,在其名字之前放上一个变量,即是一个方法。这个附加的参数会将该函数附加到这种类型上,即相当于为这种类型定义了一个独占的方法。
下面的代码里那个附加的参数p,叫做方法的接收器(receiver)
package geometry
import "math"
type Point struct{ X, Y float64 }
// traditional function
func Distance(p, q Point) float64 {
return math.Hypot(q.X-p.X, q.Y-p.Y)
}
// same thing, but as a method of the Point type
func (p Point) Distance(q Point) float64 {
return math.Hypot(q.X-p.X, q.Y-p.Y)
}
复制代码
方法的调用:
p := Point{1, 2}
q := Point{4, 6}
fmt.Println(Distance(p, q)) // "5", function call
fmt.Println(p.Distance(q)) // "5", method call
复制代码
基于指针对象的方法
我们就可以用其指针而不是对象来声明方法
func (p *Point) ScaleBy(factor float64) {
p.X *= factor
p.Y *= factor
}
复制代码
在声明方法时,如果一个类型名本身是一个指针的话,是不允许其出现在接收器中的
type P *int
func (P) f() { /* ... */ } // compile error: invalid receiver type
复制代码
调用指针类型方法(*Point).ScaleBy
,只要提供一个Point类型的指针即可
// plan1
r := &Point{1, 2}
r.ScaleBy(2)
fmt.Println(*r) // "{2, 4}"
// plan2
p := Point{1, 2}
pptr := &p
pptr.ScaleBy(2)
fmt.Println(p) // "{2, 4}"
//plan3
p := Point{1, 2}
(&p).ScaleBy(2)
fmt.Println(p) // "{2, 4}"
复制代码
不过后面两种方法有些笨拙。幸运的是,go语言本身在这种地方会帮到我们。如果接收器p是一个Point类型的变量,并且其方法需要一个Point指针作为接收器,我们可以用下面这种简短的写法:
p.ScaleBy(2)
复制代码
编译器会隐式地帮我们用&p去调用ScaleBy这个方法。这种简写方法只适用于“变量”,包括struct里的字段比如p.X,以及array和slice内的元素比如perim[0]。我们不能通过一个无法取到地址的接收器来调用指针方法,比如临时变量的内存地址就无法获取得到:
Point{1, 2}.ScaleBy(2) // compile error: can't take address of Point literal
复制代码