#13 Goで学ぶクラスの基本

Goには他の言語のような「クラス」という単語は存在せず、代わりにstructとメソッドを組み合わせて似たようなことを表現します。この記事では、Goにおけるクラスに相当する仕組みの基本を、つまずきやすいポイントも含めて解説します。

structでデータを定義する

type Person struct { Name string }

構造体にメソッドを追加する

Goでは、関数の前に対象となる構造体を書くことで、メソッドのように扱えます。

func (p Person) Greet() { fmt.Println("こんにちは、" + p.Name + "です") }

(p Person)の部分は「レシーバー」と呼ばれ、このメソッドがどの構造体に属するかを表します。

インスタンスを作って使う

person := Person{Name: "太郎"} person.Greet()

値レシーバーとポインタレシーバーの違い

レシーバーには、上記のような「値レシーバー」(p Person)と、「ポインタレシーバー」(p *Person)の2種類があります。この違いはGo初心者が特につまずきやすいポイントです。

// 値レシーバー: 構造体のコピーに対して操作する。呼び出し元は変化しない func (p Person) Rename(newName string) { p.Name = newName // ここで変更しても元のpersonは変わらない } // ポインタレシーバー: 元の構造体そのものを操作する。呼び出し元も変化する func (p *Person) RenameByRef(newName string) { p.Name = newName // 元のpersonのNameが実際に変わる }

「メソッド内でフィールドの値を書き換えたい」場合は、ポインタレシーバーを使う必要があります。迷ったら、大きな構造体やフィールドを変更するメソッドにはポインタレシーバーを使う、というのがGoでの一般的な指針です。

インターフェースで「振る舞い」をそろえる

Goには継承がありませんが、代わりに「インターフェース」を使って、異なる構造体に共通の振る舞いを持たせられます。

type Greeter interface { Greet() } // Person型はGreet()メソッドを持つので、自動的にGreeterインターフェースを満たす

他の言語のように「implements」と明示的に書く必要がなく、必要なメソッドさえ実装していれば自動的にそのインターフェースを満たしたとみなされる点が、Goらしい特徴です。

Goならではの注意点

Goには「継承」という、他のクラスの機能をそのまま引き継ぐ仕組みが存在しません。代わりに、構造体の中に別の構造体を埋め込む「コンポジション」という考え方で、似たようなことを実現します。これはGoの「シンプルさを保つ」という設計思想の表れです。また、フィールド名や関数名の先頭を小文字にすると、そのパッケージの外からはアクセスできなくなる「非公開」の扱いになります(先頭が大文字だと公開)。他の言語のprivate/publicのようなキーワードが無い分、命名規則そのものがアクセス制御を兼ねている点も覚えておきましょう。

まとめ

Goではstructとレシーバー付きの関数を組み合わせて、クラスに似た仕組みを作ります。値レシーバーとポインタレシーバーの使い分け、インターフェースによる振る舞いの共通化、大文字・小文字によるアクセス制御にも慣れていきましょう。


本ページはプロモーションを含みます。

参考書籍(PR)

Goをもっと学びたい方には「Go言語入門」がおすすめです。


PR

コードを書かずに自動化したい方へ

「学んだけど自分の作業に組み込む時間がない」という方向けに、ダブルクリックで動く Windows専用の自動化ツールをオーダーメイドで作成しています。気になる方は こちらをご覧ください。

コメント

このブログの人気の投稿

#25 Rustで学ぶAI API(ChatGPT等)の呼び出し方の基本

#8 C++で学ぶ文字列操作の基本

#16 TypeScriptで学ぶ辞書型(マップ)の基本