クラスとオブジェクトの関係性（Go 言語編）

面白い記事を見つけたので。

- [クラスとオブジェクトの関係性]

これを [Go 言語]に置き換えて語り直してみます。なお，私の個人ブログでもオブジェクトについて解説しているので，こちらも参考にどうぞ。

- [Go 言語における「オブジェクト」 — プログラミング言語 Go | text.Baldanders.info](http://text.baldanders.info/golang/object-oriented-programming/)
- [インスタンスの生成と Functional Options パターン — プログラミング言語 Go | text.Baldanders.info](http://text.baldanders.info/golang/functional-options-pattern/)

----

## たい焼きの型（クラス）を作ってみる

「クラス」とは 名前，属性，操作 の3つの情報を持つ構造を定義したものです。「[クラスとオブジェクトの関係性]」の「たい焼き」クラスを例にすると

- 名前：
    - Taiyaki
- 属性：（なし）
- 操作：
    - atama
    - shippo

という構造を指します。言い方を変えるなら上記の構造を記述できるものであればクラスとして定義できます。

ちなみに，ひとつのクラスに対してユニークな名前が1つのみ必ず存在します。属性と操作はそれぞれゼロ個以上存在します。

「[クラスとオブジェクトの関係性]」では Ruby を使って記述していますが， Ruby にはクラスを定義するためのキーワード `class` が存在します。

```ruby
class Taiyaki
    def atama
        puts "たい焼きの頭の方にはあんこがいっぱい入っている"
    end

    def shippo
        puts "たい焼きの尻尾にはあんこがほとんど入っていない"
        puts "しかしカリカリしていて美味しい"
    end
end
```

一方， [Go 言語]には Ruby で言うところの `class` に相当する構文は存在しません。その代わり [Go 言語]ではキーワード `type` を使った型宣言を使います。

```go
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 におけるインスタンス生成は以下のように記述するようです。

```ruby
taiyakikun_1gou = Taiyaki.new
taiyakikun_2gou = Taiyaki.new
```

このように，ひとつのクラスに対していくつでもインスタンスを生成できます。

一方， [Go 言語]でインスタンスを生成する方法はいくつかあるのですが，一番簡単なのは `var` キーワードによる宣言構文です。

```go
var taiyakikun1gou Taiyaki
var taiyakikun2gou Taiyaki
```

あるいは，まとめて

```go
var taiyakikun1gou, taiyakikun2gou Taiyaki
```
とも書けます。別の記述としては `new()` 関数を使い

```go
taiyakikun1gou := new(Taiyaki)
taiyakikun2gou := new(Taiyaki)
```

と書くこともできます。

Ruby の `new` はクラス・メソッドで（`class` 定義の内容によって）引数を含めることができ，これによってインスタンスの内部状態を初期化できます。

一方の [Go 言語]の `var` や `:=` は宣言構文です[^st]。 [Go 言語]でインスタンス生成時に初期化するには

[^st]: `taiyakikun1gou := new(Taiyaki)` は `var taiyakikun1gou = new(Taiyaki)` と同義です。また `new()` 関数の返り値はインスタンスそのものではなく，インスタンスへの参照（ポインタ）が返ります。

```go
taiyakikun1gou := &Taiyaki{}
```

のようにリテラルで表現するか

```go
func New() *Taiyaki {
	return &Taiyaki{}
}
```

のようにインスタンスを生成（Ruby で言うところのインスタンス化）する関数を作るのがセオリーになっています。

では，最終的な [Go 言語]のコードを以下に示すとしましょう。

```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 言語]でクラスやインスタンスについてちょっとだけ掘り下げて考えてみました。

[Go 言語]: https://golang.org/ "The Go Programming Language"
[クラスとオブジェクトの関係性]: https://qiita.com/daisakuhazui/items/920bca4fe1ad28c77cef

----