go的方法

方法

方法的声明: 在函数声明时,在其名字之前放上一个变量,即是一个方法。这个附加的参数会将该函数附加到这种类型上,即相当于为这种类型定义了一个独占的方法。

下面的代码里那个附加的参数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
复制代码

通过嵌入结构体来拓展类型

方法值和方法表达式

封装

猜你喜欢

转载自juejin.im/post/7030989570778857509