🔀

制御文 — if/forは似てるがwhileがない

Rubyのeach/map/selectが恋しくなるforループの世界

Rubyで配列を回す時[1,2,3].each { |n| puts n }と書く。ブロックを渡すパターンが身についている。

Goではfor _, n := range []int{1,2,3} { fmt.Println(n) }。ブロックもない、イテレータもない。forループが全て。

whileがない

Rubyのwhile condition do ... endに相当するGoコードはfor condition { ... }。キーワードはforなのにwhileのように動作する。Goはループをforひとつに統一した。

無限ループもfor { ... } — Rubyのloop do ... endに相当。

.map、.selectがない

Rubyでnumbers.map { |n| n * 2 }一行で済むものがGoでは3行:

result := make([]int, len(numbers))
for i, n := range numbers {
    result[i] = n * 2
}

Goコミュニティはこれを「明示的」と呼ぶ。Ruby開発者は「冗長」と呼ぶ。どちらも正しい。

ifに括弧がない

Rubyもif条件に括弧を使わない。Goも使わない。似ている。ただしGoのifは短い宣言文を含められる:if err := doSomething(); err != nil { ... } — Rubyにないパターンだ。

switchが強力

Rubyのcase/whenはパターンマッチングが可能。Goのswitchも似ているが、fallthroughがデフォルト無効(Cと逆)。型switchもある — switch v := x.(type) { case int: ... }はRubyのcase x when Integerパターンに似ている。

RubyからGoへ

1

Ruby: while/until/loop → Go: forひとつで全部(whileなし)

2

Ruby: .each { |x| } ブロックパターン → Go: for _, x := range パターン

3

Ruby: .map/.selectメソッドチェーン → Go: forループ直接記述(組み込み関数なし)

4

Ruby: case/when → Go: switch(fallthroughデフォルト無効、型switch対応)

メリット

  • forひとつに統一 — 覚えることが少ない。while、until、loopなどのバリエーションなし
  • ifに短い宣言文を含められる — errハンドリングがスコープ内で綺麗に完結

デメリット

  • .map/.select/.reduceがなくコレクション処理コードが3〜5倍長くなる
  • Rubyのブロック/Proc/Lambdaのような第一級関数パターンがなく表現力が落ちる

ユースケース

RubyのEnumerableメソッドチェーン習慣をGoスタイルに転換する時 for range + ifの組み合わせでRubyの.select.mapパターンを実装する時