Go言語のオブジェクト指向の特徴を完全ガイド!初心者でも理解できる他言語との違い
生徒
「オブジェクト指向ってよく聞きますけど、Go言語でも使えるんですか?」
先生
「Go言語にもオブジェクト指向の考え方はありますが、少し独特なんですよ。他の言語と違ってクラスは使いません。」
生徒
「えっ?じゃあ、どうやってオブジェクトっぽく使うんですか?」
先生
「Goでは『構造体』と『メソッド』、そして『インターフェース』を組み合わせることで、オブジェクト指向のようなことができます。詳しく見てみましょう。」
1. オブジェクト指向とは何か?
オブジェクト指向(Object-Oriented Programming / OOP)は、データ(状態)と処理(振る舞い)をひとつの単位にまとめて考える方法です。身近な例でいえば「車」というモノは、メーカー名や色といった情報を持ち、「クラクションを鳴らす」「走る」といった動きを行えます。OOPでは、この「情報+動き」をひとつに束ねて扱うので、プログラムの見通しが良くなり、初心者でも動作のイメージを掴みやすくなります。
以下は、OOPの雰囲気をつかむための短いサンプルです。ここでは「車」というモノが、自分の情報を使って動作(メソッド)を実行する様子を示しています。
package main
import "fmt"
// モノ:車(情報=Brand、動き=Honk)
type Car struct {
Brand string // 情報(状態)
}
// 動き(振る舞い)
func (c Car) Honk() {
fmt.Println(c.Brand + "がプップー!")
}
func main() {
car := Car{Brand: "トヨタ"} // モノを作る
car.Honk() // モノに「動き」をさせる
}
ポイントは、「車」というまとまりが自分の情報(Brand)を覚えていて、必要なときに自分の動き(Honk)を呼び出せることです。これがオブジェクト指向の基本発想で、モノごとをそのままプログラムに写すイメージだと理解しやすいでしょう。
2. Go言語はクラスを使わない
多くのオブジェクト指向言語(JavaやPythonなど)では、「クラス」というものを定義してから、それを使って「インスタンス」を作ります。ですが、Go言語にはクラスという概念がありません。その代わりに「構造体(struct)」を使ってデータをまとめます。
構造体は「複数の値をまとめて扱う箱」のようなもので、これにメソッドを定義することでオブジェクトのように使うことができます。
3. 構造体とメソッドを使ってオブジェクトのように扱う
構造体とメソッドを組み合わせることで、Go言語ではオブジェクト指向のようなスタイルでプログラムを書くことができます。以下はその例です。
type Car struct {
Brand string
Speed int
}
func (c Car) Drive() {
fmt.Println(c.Brand + "が走っています。時速", c.Speed, "km/h")
}
func main() {
car := Car{"トヨタ", 80}
car.Drive()
}
このように、構造体Carに対してDriveというメソッドを定義することで、オブジェクトっぽい使い方ができます。
4. Go言語は継承ではなく「埋め込み(埋め込み構造体)」を使う
他のオブジェクト指向言語では「クラスの継承」を使って機能を受け継ぎます。Go言語では「埋め込み」という方法を使って、ある構造体の中に別の構造体を含めることで、似たような効果を得られます。
type Animal struct {
Name string
}
func (a Animal) Speak() {
fmt.Println(a.Name + "が鳴いています")
}
type Dog struct {
Animal
Breed string
}
func main() {
dog := Dog{Animal{"ポチ"}, "柴犬"}
dog.Speak()
}
このように、Dog構造体はAnimalの機能(Speakメソッド)を自然に使えるようになります。
5. インターフェースを使って柔軟な設計ができる
Go言語のもうひとつの特徴は、「インターフェース」です。インターフェースとは「この機能を持っているものなら誰でもOK」というルールのようなもので、具体的な実装を意識せずにプログラムを書くことができます。
Go言語では「構造体が自動的にインターフェースを満たす」しくみがあり、他の言語に比べて非常に柔軟です。
type Speaker interface {
Speak()
}
type Cat struct {
Name string
}
func (c Cat) Speak() {
fmt.Println(c.Name + "がニャーと鳴きました")
}
func MakeItSpeak(s Speaker) {
s.Speak()
}
func main() {
cat := Cat{"ミケ"}
MakeItSpeak(cat)
}
このように、Cat構造体はSpeakerインターフェースの条件(Speakメソッドを持つ)を満たしているので、関数MakeItSpeakに渡すことができます。
6. 他の言語との違い
- クラスがない:Go言語では構造体で代用します。
- 継承がない:埋め込み構造体を使います。
- インターフェースの明示的な宣言が不要:自動的に満たされる仕組み。
- シンプルで明確な構文:初心者にも理解しやすい。
まとめ
ここまでGo言語のオブジェクト指向を見てきましたが、あらためて振り返ってみると、Goは難しい専門用語を覚えなくても自然な流れで書けるように工夫された言語だとわかります。クラスという決まった枠を用意せずに、現実世界の「モノ」に近い形でデータをまとめ、そのデータに関連した動きをメソッドとして記述するだけで、オブジェクト指向らしいあつかいができます。初心者にとっても、まずは「構造体で情報をひとまとめにする」「メソッドで動きを書く」という二つの基本さえ覚えておけば、複雑な前提知識がなくても理解できる書き方になっています。 とくに面白いのは、Goでは拡張や再利用もむずかしくないことです。他の言語ではクラスの継承が中心になりますが、Goでは埋め込みによって別の構造体の性質を「そのまま持たせる」ことができます。実際の開発では、「共通の性質をまとめておきたい」「特定の機能だけ別の構造体にも使いたい」という場面が多くあります。そんなとき、埋め込みはシンプルな文法で使えるため、余計な設定を覚えなくても自然に記述できます。 さらに、インターフェースの柔軟さもGoならではの特徴です。他の言語では「実装します」という宣言が必要ですが、Goでは必要なメソッドがそろっているだけで条件を満たすため、コードが増えても管理が複雑になりません。同じルールで動く構造体を横に並べるように扱えるので、規模が大きくなっても読みやすさが保たれます。実務でも利用される理由はここにあり、すっきりした文法が保守や変更に強いコードにつながります。 たとえば、動物が鳴く処理を追加したいとき、共通で持たせたいルールだけをインターフェースにしておけば、どんな動物でも同じ関数に渡せます。種類が増えても、必要なメソッドだけ用意すればよいため、共通化と追加が両立できます。
短いサンプルでふりかえり
ここでは実際に、構造体・メソッド・インターフェースがそろって動く簡単な例をもう一度見てみましょう。
package main
import "fmt"
// 共通ルール:鳴くことができるもの
type Speaker interface {
Speak()
}
// 犬
type Dog struct {
Name string
}
func (d Dog) Speak() {
fmt.Println(d.Name + " がワン!と吠えます")
}
// 猫
type Cat struct {
Name string
}
func (c Cat) Speak() {
fmt.Println(c.Name + " がニャーと鳴きます")
}
// どんなSpeakerでも鳴かせられる
func MakeSound(s Speaker) {
s.Speak()
}
func main() {
dog := Dog{Name: "ポチ"}
cat := Cat{Name: "タマ"}
MakeSound(dog)
MakeSound(cat)
}
この短いコードでも、構造体でデータをまとめ、メソッドで動きを書き、インターフェースで共通のルールを作れることが確認できます。Goでは特別な宣言をしなくても、メソッドを持っていればそのままインターフェースを満たします。初心者にも扱いやすく、覚える手順が少なくてすむという利点になります。 現実の開発でも「同じように扱いたい型が複数ある」「共通の関数でまとめたい」といった場面がよくあります。そのたびに複雑な設定を増やす必要がないため、プログラム全体がすっきりしたまま維持できるというのもGoの魅力です。
生徒
「Go言語ってクラスがないから難しいのかと思っていましたけど、むしろ覚えることが少ないんですね。」
先生
「そうなんです。クラスのキーワードを覚えたり、複雑な継承関係を設計したりしなくても、構造体とメソッドだけで自然にオブジェクト指向の考え方を取り入れられます。」
生徒
「埋め込みっていう仕組みも、書き方がすごくシンプルでしたね。Animalを入れただけで、Dogが動きを使えるのは驚きでした。」
先生
「そうでしょう。継承ほど複雑な概念を持ち込まず、『この構造体はこれを持っている』という考え方で済むので、読み返したときにも理解しやすいんですよ。」
生徒
「インターフェースも宣言いらずで使えるって新鮮でした。Javaだと『implements』みたいな書き方が必要ですよね。」
先生
「Goでは必要なメソッドさえ用意しておけば条件を満たすので、型をまたいで共通の処理を呼び出したいときに便利です。規模が大きくなっても管理が混乱しにくく、読みやすさが保てるという強みにつながります。」
生徒
「なるほど…。データは構造体にまとめて、動きはメソッドに書いて、必要ならインターフェースで共通化。これができれば実践にも応用できそうですね!」
先生
「そういうことです。まずは小さなサンプルから試して、仕組みを少しずつ体に覚えさせるのが一番です。Goは堅苦しくない文法なので、初心者でも楽しく覚えられると思いますよ。」