Go言語学習も8日目に入りました!
今日は [Go Tour(日本語版)]の「Methods and Interfaces」セクションに取り組んでみました。
前回までの取り組みはコチラ
このあたりから、少しオブジェクト指向っぽい雰囲気が出てきますが…
ゆっくりコードを動かして理解していくスタイルで進めていきます!
まずはメソッドを定義してみよう
Goでは、構造体に対してクラスのメンバーのようにメソッドを定義できます。
package main import "fmt" type Rectangle struct { Width float64 Height float64 } // メソッド定義:値レシーバ func (r Rectangle) Area() float64 { return r.Width * r.Height } func main() { rect := Rectangle{Width: 5, Height: 3} fmt.Println("面積:", rect.Area()) // 面積: 15 }
ポイント
func (r Rectangle)
← この(r Rectangle)
の部分が「メソッドレシーバ」Rectangle
型にArea()
という機能を“追加”しているイメージ
インターフェースと似てますよね。なんか、後付けでメソッドが定義できている感じが新鮮。 C#などですと、クラス内に作らないと。というイメージが強く。。 それを打破するために、自分なりにはオブジェクトに後でメソッドを追加する。みたいな感じで認識しようとしています。
ポインタレシーバって何?
Goでは、メソッドのレシーバに「値」か「ポインタ」かを選べます。
以下のような書き方です
func (r *Rectangle) Scale(factor float64) { r.Width *= factor r.Height *= factor }
ポイントは *Rectangle
というポインタ型を使っていること。
func main() { rect := Rectangle{Width: 2, Height: 4} rect.Scale(2) // Width: 4, Height: 8 fmt.Println("拡大後:", rect) }
ポインタレシーバを使う理由
- メソッド内で「構造体の値を書き換えたい」場合に必要
- 値レシーバ(
r Rectangle
)だとコピーされるので元の値は変わらない!
値レシーバ vs ポインタレシーバの違い:簡単コードで比較!
package main import "fmt" type Counter struct { Count int } func (c Counter) IncrementByValue() { c.Count++ } func (c *Counter) IncrementByPointer() { c.Count++ } func main() { c := Counter{} c.IncrementByValue() fmt.Println("値レシーバ:", c.Count) // → 0(変わらない) c.IncrementByPointer() fmt.Println("ポインタレシーバ:", c.Count) // → 1(反映される!) }
じゃあ実務ではどっちを使えばいいの?
一般的な指針?
- 構造体の中身を「変更したい」→ ポインタレシーバ
- 単に「読み取るだけ」→ 値レシーバ(コピーでもOK)
- 複数のメソッドがある場合は統一するのが吉(バラバラだと混乱…)
実務ではほとんどがポインタレシーバになるんじゃないかな?
今日のまとめ
Go言語8日目の学習ポイントまとめ
- メソッドは
func (x Type) MethodName()
の形で定義できる - 構造体に機能を持たせることで、使いやすく整理されたコードに!
- ポインタレシーバを使えば、構造体の中身を更新できる
- 値レシーバだとコピーになるため、元のデータは変わらない
- 「メソッドはオブジェクトっぽく機能を“ひもづける”もの」と捉えると理解しやすい!
文系SE的にも、ここまで来ると 「Goってクラスっぽいこともできるんだな〜」 って気づきが増えてきました。
(以下、広告を含みます)