メソッド

メソッドは、構造体(の型)と結びつけられた関数だ。Go はオブジェクト指向プログラミング言語ではないけど、このメソッドや構造体の埋め込み(これについては後で書くつもり)によって、オブジェクト指向的なプログラミングができるようになっている。
例を挙げよう。
前のエントリでは平面上の点を表す Point 構造体と、2点間の距離を求める distance 関数を作った。ここでもう一つ、3次元空間の点を表す Point3d 構造体を作る。この2点間の距離を求める関数を考えたとき、distance という名前は使えない。すでに名前を使ってしまっているからだ。
ところが、これらをそれぞれの構造体のメソッドにすれば、両方とも distance という名前にできる。
メソッドの一般亭な定義は次の通り。

func (仮引数 *型) 関数名(仮引数, ...) {
    処理
}

ここで、関数名の前のカッコの中にある仮引数をレシーバと言い、このメソッドはレシーバの型と結びつけられる。これで、PointPoint3d の両方の構造体に、同じ distance という名前のメソッドが定義できるわけだ。
実際に書いてみよう。

package main

import (
    "fmt"
    "math"
)

type Point struct {
    x, y float64
}

type Point3d struct {
    x, y, z float64
}

func newPoint(x, y float64) *Point {
    p := new(Point)
    p.x, p.y = x, y
    return p
}

func newPoint3d(x, y, z float64) *Point3d {
    p := new(Point3d)
    p.x, p.y, p.z = x, y, z
    return p
}

func (p *Point) distance(q *Point) float64 {
    dx := p.x - q.x
    dy := p.y - q.y
    return math.Sqrt(dx * dx + dy * dy)
}

func (p *Point3d) distance(q *Point3d) float64 {
    dx := p.x - q.x
    dy := p.y - q.y
    dz := p.z - q.z
    return math.Sqrt(dx * dx + dy * dy + dz * dz)
}

func main() {
    p1 := newPoint(0.0, 0.0)
    p2 := newPoint(10.0, 10.0)
    q1 := newPoint3d(0.0, 0.0, 0.0)
    q2 := newPoint3d(10.0, 10.0, 10.0)

    fmt.Println(p1.distance(p2))
    fmt.Println(q1.distance(q2))
}
^o^ > go run method.go
14.142135623730951
17.320508075688775