12
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

フラー株式会社Advent Calendar 2021

Day 6

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

Last updated at Posted at 2021-12-05

この記事は、フラー株式会社 Advent Calendar 2021の6日目の記事です。

5日目の記事は @m-coder さんによる DroidKaigi2021に登壇した話 でした。


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

型があるとうれしい

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

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

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

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

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

クラスは無い

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

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

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

type FooBar struct {
	foo string
	bar int
}

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

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

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

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

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

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

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でやるとしたらこんな感じでしょうか。

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では複数単語をつなげた名称をつけるときはキャメルケースにする風習です。

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

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

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

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

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

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

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

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.gonice/bar.goの一番上にはpackage niceと書いておきます。

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

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

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


以上です。

12
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?