Go语言的面向对象,OOP

一、方法

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

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

上方代码里附加的参数p,叫做方法的接收器(receiver)。Go语言中不像其它语言使用this或self作为接收器,我们可以任意选择接收器的名字。为保持其在方法间传递时的一致性和简短性,建议使用其类型的第一字母。

当接收器变量本身比较大时(拷贝消耗资源较多),我们可以用其指针而不是对象来声明方法。如:

func (p *Point) ScaleBy(factor float64) {
    p.X *= factor
    p.Y *= factor
}

p := Point{1, 2}
(&p).ScaleBy(2)
fmt.Println(p) // "{2, 4}"

如果接收器p是一个Point类型的变量,并且其方法需要一个Point指针作为接收器,我们可以简写为p.ScaleBy(2)。编译器会隐式的帮我们用&p去调用ScaleBy这个方法。

这种简写只适用于"变量",不能通过一个无法取得地址的接收器来调用指针方法,如:Point{1,2}.scaleBy(2)。

GO语言中没有类似C++的Class关键字,以及直接的对象继承。不过可以通过嵌入结构体来扩展类型,在类型中内嵌的匿名字段也可以是一个命名类型的指针。如下:

type ColoredPoint struct {
    *Point
    color.RGBA
}

待续