Rubyやってた人間がGo始めて思ったこと

この記事は、[フラー株式会社 Advent Calendar 2021](https://qiita.com/advent-calendar/2021/fuller-inc)の6日目の記事です。

5日目の記事は [@m-coder](https://qiita.com/m-coder) さんによる [DroidKaigi2021に登壇した話](https://note.com/m_coder/n/n74901d195d83) でした。

---

私は元々Ruby on Railsで開発をしていたのですが、最近転職しまして、Goに入門しました。
Goやり始めて「へぇ〜」と思ったことを書いてみます。

## 型があるとうれしい

私は静的型付けの言語をこれまであまり触ったことがなかったのですが、型がちゃんと決まってるとありがたいですね。

エディタ(VSCodeを使っています)の補完機能がバリバリ効いて、

- この変数にどんな値が入っているのか
- この変数はどんなメソッドが使えるか
- このメソッドにどんな値を入れればいいか

などを教えてもらえるので、サクサクコードを書き進められます。

Rubyだと「最近入力した単語」くらいしかエディタの候補に出してもらえないので、ファイルを行き来してメソッドの中身とかを確認する必要があったりしたので、そこが地味に手間だったな〜と思います。

## クラスは無い

Goではクラスを定義する仕組みが無いんですね。

他の言語で言うクラス的なことをやるには、`struct`(構造体)を使って任意の型のフィールドを持つ型を定義して、その型に対するメソッド定義を外側で(型定義とは別に)やる、みたいな流れになります。

例えば`foo`という`string`型のフィールドと、`bar`という`int`型のフィールドを持った`FooBar`という型を定義したいな〜というときはこういう風に書きます。

```go
type FooBar struct {
	foo string
	bar int
}
```

で、`FooBar`型のインスタンスに紐づくメソッド(Rubyで言うところのインスタンスメソッド)を定義したいな〜というときは、型定義とは別に、以下のようなメソッド定義を書きます。

```go
func (f FooBar) SayFoo() {
	fmt.Sprint(f.foo)
}
```

`func`キーワードの後に`(f FooBar)`とあるのが、「この関数は`FooBar`型の変数`f`がレシーバーになるよ」という意味で、これにより`FooBar`型のインスタンスで`SayFoo()`というメソッドを使用できるようになります。

結果として、以下のように`SayFoo()`メソッドを備えた`FooBar`型が使用できるようになります。

```go
func main() {
	f := FooBar{foo: "Woooo!", bar: 1} // FooBar型のインスタンスを生成して、`f`に代入
	f.SayFoo() // `f`のメソッド`SayFoo()`を実行
}
```

全体のコードとしてはこうなります。

```ruby
package main

import "fmt"

type FooBar struct {
	foo string
	bar int
}

func (f FooBar) SayFoo() {
	fmt.Print(f.foo)
}

func main() {
	f := FooBar{foo: "Woooo!", bar: 1}
	f.SayFoo()
}
```

ちなみに、同じようなことをRubyでやるとしたらこんな感じでしょうか。

```ruby
class FooBar
  def initialize(attr = {})
    @foo = attr[:foo].to_s
    @bar = attr[:bar].to_i
  end

  def say_foo()
    puts @foo
  end
end

foo_bar = FooBar.new(foo: "Woooo!", bar: 1)
foo_bar.say_foo
```

Goの方が型定義とメソッド定義が分離されてスッキリしてて良いね〜ということなんでしょうかね。

## 変数名は短くする

Go界隈だと、割と短い変数名をつける風潮があるように感じます。1文字だったり略語にしたり。

Rubyだと2単語をアンダーバーでつなげた変数名とかを良く書いていた気がします。

型が明確になっているし、説明的な変数名をつけないといけないような見通しの悪いメソッドは書くもんじゃねえぞ、というノリなんでしょうかね。

まあGoに入ればGoに従えということで。

## 略語は全部大文字にする

Goでは複数単語をつなげた名称をつけるときはキャメルケースにする風習です。

その際に`ID`や`URL`といった、略語はすべて大文字のままにしておくのが良しとされているようです。

例えば`userID`とか`baseURL`みたいな感じです。

JavaScriptなんかだと`userId`とか`baseUrl`みたいにしちゃいそうな気がしますが、まあGoに入ればGoに従えということで。

## 構造体のタグというものがある

Goの構造体のフィールド定義では、型に加えて「タグ」と呼ばれる情報を付与することができます。フィールドのオプションみたいなもののようです。

例えばGoの標準パッケージであるjsonパッケージを使うときに、読み込むJSONのキーと構造体のフィールド名を関連付けるのに使われます。

こんな感じで書き、`json:"id"`という部分がタグです。

```go
type User struct {
	ID int `json:"id"`
	Name string `json:"name"`
}
```

こうすることで、「JSONの"id"というキーが、`User`型の`ID`フィールドに対応しているよ〜」ということがjsonパッケージに伝えられて良い感じにやってくれるようになります。へぇ〜。

## ディレクトリごとにパッケージとしてまとめられる

Goではプロジェクト内にディレクトリを作成し、その中に`.go`ファイルを配置すると、別パッケージとして扱えるようになります。(同じディレクトリに複数パッケージのソースコードを配置することはできない)
また、同じパッケージのソースコード同士では、importを書かなくても別ファイルの内容を参照できます。

例えばこんな感じのディレクトリ構成になっていたとして、

```
.
├── main.go
└── nice
    ├── bar.go
    └── foo.go
```

`nice/foo.go`と`nice/bar.go`の一番上には`package nice`と書いておきます。

そうすると`main.go`内では、`nice`パッケージをimportすることで、`nice`パッケージで定義した型や関数を`nice.HogeHoge`といった形で参照できるようになります。

また、`nice/foo.go`と`nice/bar.go`の中では、同じパッケージ内なので、内容を相互に参照可能です。

割と分かりやすいので、コードの整理をしやすそうだな〜という雰囲気を感じます。

---

以上です。