【Ruby】繰り返し文のまとめ

# はじめに
こんにちは、絶賛Ruby勉強中のものです。
本日はRubyで出てくる繰り返し文について簡単にまとめようと思い記事にしました。
繰り返すという点では同じですが、それぞれ違う用途で使われることが多くわからなくなってしまうことがあると思うので初心者向けではありますが見ていきたいと思います

# Rubyの繰り返し文
まずはRubyの繰り返し文とひとくくりにしていますが、制御構文とメソッドにその性質をもつものがあります。
制御構文は`if`とか`until`、`case`などのことを言います。なので本来は一緒に紹介するものではないのですが、繰り返すというグループで囲むと同じなのでまとめて紹介していきます。
* times(メソッド)
* for(制御構文)
* while(制御構文)
* until(制御構文)
* each(メソッド)
* loop(メソッド)

## times
`times`は「○回繰り返す」と決まっている場合に便利な構文です。
例えば、5.timesとすると5回だけ処理を繰り返します。
```ruby:times1.rb
5.times do |i|
  puts i
end
# 0
# 1
# 2
# 3
# 4
```
また、do ... endの代わりに中括弧 { ... }を使って以下のように短く記述することも可能です。
```ruby:times2.rb
5.times { |i| puts i }
```

## for
ruby以外のほかの言語の繰り返しといえば`for`を連想しますよね。
`for`は配列や範囲のすべての要素に対して繰り返し処理をしたいときに使用されます。
```ruby:for1.rb
sum = 0
for i in 1..3
  sum += i
end
puts sum
# 6
```
Rubyの`fo`r文は、すべての要素を繰り返し処理する時に便利ですが、Rubyでは一般的に`each`の方がよく使われます。
理由の一つは、`for`はループの外でも変数が参照できてしまうためです。

```ruby:scope.rb
# forの場合
for i in (1..3)
  puts i
end
puts i  # forではループ外でも変数iが使える

# eachの場合
(1..3).each do |j|
  puts j
end
puts j  # eachではエラーが出る
```
`each`はブロックを使用しており、スコープが限定されるため、ループ外で変数が参照できません。
このことで思わぬ副作用を防ぎ、コードの安全性が向上します。

## while
条件が真である限り繰り返しを行いたい場合に使用されます。
```ruby:while1.rb
total = 0
i = 1
while i <= 5
  total += i
  i += 1
end
puts total
# 15
```
上記のように5回繰り返す場合、`for`や`times`でも同じ結果を得られますが、条件を自由に設定できる点が`while`の特徴です。
例えば、以下のように合計が50に達するまで処理を繰り返す場合などは`while`が適しています。
```ruby:while2.rb
total = 0
i = 1
while total < 50
  total += i
  i += 1
end
puts total
```
### whileの追記
コメントで教えていただいたのですが、実は`while`はあまり出番がないようです！
教材ベースで学んでおいてこういった気づきがあるのも面白いですね。
では具体的にどういうことが説明してきます。`while2.rb`のコードについてみていきましょう
```ruby:step.rb
total = 0
1.step do
  total += _1
  break if total >= 50
end
puts total
```
>行数では 1 行しか減っていませんが，「i の値を初期化する」「i の値を 1 ずつ増やす」という処理をいちいち書かなてくよいぶん，把握しやすいように思います。
（Numeric#step は初期値に増分と上限・下限を与えて繰り返すイテレーターです。ここでは増分〔既定値 1〕を略し，上限を無しとして使っています）

上記のようにコメントをいただきました。
`step`というメソッドは初めて知ったのですが、`while`よりも冗長すぎなくて見やすいコードになりますね。
そう考えると`while`の出番ってほんとに少ないのかもしれません。

## until
条件が「偽」になるまで繰り返したい場合に使用します。
`if`にも`unless`という条件が偽の場合に処理を行う条件式がありましたが、`until`は`while`の逆バージョンと思っていただければ大丈夫です
```ruby:unless.rb
total = 0
i = 1
unless total >= 50
  total += i
  i += 1
end
puts total
```
これは`while2.rb`を`unless`に書き直したコードです。`while`とは条件式が逆になっています

## each
Rubyでは`for`の代わりに、配列や範囲オブジェクトに対する繰り返し処理には`each`が多く使用されます。
`for`に比べてスコープが狭くなり、思わぬ副作用を防ぐことができるためです。
```ruby:each1.rb
sum = 0
(1..3).each do |i|
  sum += 1
end
puts sum
```

## loop(追記)
こちらもコメントいただいたので追記です。
loopは無限ループ作るときくらいしか使わないと習ったのですが、`while`の代わりに使う場面があるようです。

> 繰り返し処理の典型的なパターンの一つに以下のようなものがあります。
* 処理 A を行う
* その結果次第でループを抜ける
* 抜けなかった場合は処理 B を行う
* 以上を繰り返す
ここで，処理 A が非常に単純なとき，while で書けます：

```ruby:short_while.rb
while [処理 A とその結果による条件式]
  処理 B
end
```

>しかし，[処理 A とその結果による条件式] が単純な式で書けない場合，非常に見づらいコードになります。
こういうときは `loop` メソッドを使って

```ruby:loop.rb
loop do
  処理 A
  break if 条件式
  処理 B
end
```
>と書くのがよい場合があります。

`loop`は無限ループのみしか使わない、いわばのけものと扱わずにこんなにスマートな使い方があることを教えていただきました。
他にも`loop`の使い方を知っている方は教えていただけると励みになります。


# まとめ
Rubyの繰り返し文には、それぞれ独自の特徴と適した場面があります。
* 固定回数の繰り返しには `time`s
* 配列や範囲オブジェクトの要素に対して繰り返しを行うには `each`
* 自由な条件に基づく繰り返しが必要なら `while`や`until`。ただし、`while`は`each`や`loop`にとってかわられることが多く使う機会がない
* スコープを意識せず使いやすいが、制御が必要な場合は `for`よりも`each`が推奨されます