面白い記事を見つけたので。
これを Go 言語に置き換えて語り直してみます。なお,私の個人ブログでもオブジェクトについて解説しているので,こちらも参考にどうぞ。
- Go 言語における「オブジェクト」 — プログラミング言語 Go | text.Baldanders.info
- インスタンスの生成と Functional Options パターン — プログラミング言語 Go | text.Baldanders.info
たい焼きの型(クラス)を作ってみる
「クラス」とは 名前,属性,操作 の3つの情報を持つ構造を定義したものです。「クラスとオブジェクトの関係性」の「たい焼き」クラスを例にすると
- 名前:
- Taiyaki
- 属性:(なし)
- 操作:
- atama
- shippo
という構造を指します。言い方を変えるなら上記の構造を記述できるものであればクラスとして定義できます。
ちなみに,ひとつのクラスに対してユニークな名前が1つのみ必ず存在します。属性と操作はそれぞれゼロ個以上存在します。
「クラスとオブジェクトの関係性」では Ruby を使って記述していますが, Ruby にはクラスを定義するためのキーワード class
が存在します。
class Taiyaki
def atama
puts "たい焼きの頭の方にはあんこがいっぱい入っている"
end
def shippo
puts "たい焼きの尻尾にはあんこがほとんど入っていない"
puts "しかしカリカリしていて美味しい"
end
end
一方, Go 言語には Ruby で言うところの class
に相当する構文は存在しません。その代わり Go 言語ではキーワード type
を使った型宣言を使います。
type Taiyaki struct{}
func (t Taiyaki) Atama() {
fmt.Println("たい焼きの頭の方にはあんこがいっぱい入っている")
}
func (t Taiyaki) Shippo() {
fmt.Println("たい焼きの尻尾にはあんこがほとんど入っていない")
fmt.Println("しかしカリカリしていて美味しい")
}
このように type
構文によって「型」を定義します。 type
の名前がそのままクラスの名前に相当します。 Taiyaki
型 a.k.a Taiyaki
クラスには属性がないため,空の構造体 struct{}
を当てています。
func (t Taiyaki) Atama() {}
の部分は関数定義です。このうち (t Taiyaki)
の部分は「メソッド・レシーバ」と呼ばれるもので, Taiyaki
クラスに対して Atama
関数を「操作」として関連付ける働きがあります。
たい焼き(インスタンス)を作ってみる
「インスタンス(instance)」は実体とか実例とか訳されるもので,定義であるクラスから生成した実体・実例がインスタンスというわけです。
厳密にはクラスとは「クラス・オブジェクト(class object)」で,インスタンスとは「インスタンス・オブジェクト(instance object)」です。両者とも「オブジェクト」ですが意味が異なるということですね。
さて「クラスとオブジェクトの関係性」によると Ruby におけるインスタンス生成は以下のように記述するようです。
taiyakikun_1gou = Taiyaki.new
taiyakikun_2gou = Taiyaki.new
このように,ひとつのクラスに対していくつでもインスタンスを生成できます。
一方, Go 言語でインスタンスを生成する方法はいくつかあるのですが,一番簡単なのは var
キーワードによる宣言構文です。
var taiyakikun1gou Taiyaki
var taiyakikun2gou Taiyaki
あるいは,まとめて
var taiyakikun1gou, taiyakikun2gou Taiyaki
とも書けます。別の記述としては new()
関数を使い
taiyakikun1gou := new(Taiyaki)
taiyakikun2gou := new(Taiyaki)
と書くこともできます。
Ruby の new
はクラス・メソッドで(class
定義の内容によって)引数を含めることができ,これによってインスタンスの内部状態を初期化できます。
一方の Go 言語の var
や :=
は宣言構文です1。 Go 言語でインスタンス生成時に初期化するには
taiyakikun1gou := &Taiyaki{}
のようにリテラルで表現するか
func New() *Taiyaki {
return &Taiyaki{}
}
のようにインスタンスを生成(Ruby で言うところのインスタンス化)する関数を作るのがセオリーになっています。
では,最終的な Go 言語のコードを以下に示すとしましょう。
package main
import "fmt"
type Taiyaki struct{}
func (t Taiyaki) Atama() {
fmt.Println("たい焼きの頭の方にはあんこがいっぱい入っている")
}
func (t Taiyaki) Shippo() {
fmt.Println("たい焼きの尻尾にはあんこがほとんど入っていない")
fmt.Println("しかしカリカリしていて美味しい")
}
func main() {
var taiyakikun1gou Taiyaki
taiyakikun1gou.Atama()
taiyakikun1gou.Shippo()
var taiyakikun2gou Taiyaki
taiyakikun2gou.Atama()
taiyakikun2gou.Shippo()
}
まとめ
「たい焼き」クラスを通して class
キーワードのない Go 言語でクラスやインスタンスについてちょっとだけ掘り下げて考えてみました。
-
taiyakikun1gou := new(Taiyaki)
はvar taiyakikun1gou = new(Taiyaki)
と同義です。またnew()
関数の返り値はインスタンスそのものではなく,インスタンスへの参照(ポインタ)が返ります。 ↩