Help us understand the problem. What is going on with this article?

[Ruby]return,break,next それぞれの処理の終わらせ方

初めに

paizaで競プロみたいなことできるやん!!ってなってとりあえず朝の勉強初めはやる気出すために遊んでいるのですが。
その中でreturn等、処理を終わらせる記述の挙動についてわかってなかったな〜ってことがあったので書き留めておきます(正直まだ理解しきってはいない)

環境

Ruby 2.6.5

遭遇したこと

以下の様なコードを書いていました。(数値とかは問題の公表につながらない様書き換えています)

test.rb
array = [1,2,3]
ans = []

array.each do |a|
  if a >= 1
    ans << a
    return
  end
end

p ans

簡略化した処理をしていますが、僕がやりたかったのは以下の様なことでした。

配列の要素について条件を検証し、該当するものが見つかった時点でその値を空配列に入れ、繰り返し処理を終える

上記のコードで言えば一番目の1の時点でifに該当しているので、ans = [1]となり処理が終わってくれれば良いのでした。

そして上記コードを実行した結果が以下の通り。

スクリーンショット 2020-07-28 12.50.16.png

何も反応しねえ。

何もpされてこない訳です。
僕は最初これを、ansにaが入っていないから表示されていないと思い、returnでスコープが変わる・・・!?とか動揺してたんですが。
よく考えたらその場合でも p ansしたら []って感じで空の配列は表示されるはずなんですよね。

そう思って上記コードの最後に 「p array」と追記しても何も表示されなかったので、「ああーー処理が終わってんのか!」とたどり着くことができた訳です。

上記の様なケースに遭遇したため、処理を終わらせる方法について調べて出てきた3つについてまとめておこうと思います(return,break,next)

returnについて

returnはメソッドそのものを終わらせます

上記が答えです。
それについては知っていたのですが、今回の場合defでメソッドを作っていた訳じゃないので以降の処理が終了するという状況が同じであると気付けませんでした。

ここ、正直あやふやですが、今回の様に何も定義しないでやってる場合は「そのプログラム全体を範囲として終了させる」ということでしょうか。

ちなみにメソッドを終わらせるとはどういうことか例を使ってもう少し説明すると

test.rb
array = [1,2,3]
ans = []

def check
  array.each do |a|
    if a >= 1
      ans << a
      return
  end
puts "Hello"
end

上記の様なケースでcheckメソッドを実行した場合、returnが終わらせるのはeach処理ではなくcheck全てです。
なので、returnでeachの処理が終わった後、puts "Hello"されるわけではありません、ということです。
何か処理の中で使われていても、その処理だけを終わらせるのではなく、メソッドそのものを終わらせるのがreturn ですよ、ということですね。

breakについて

breakはその繰り返し処理のみを終わらせます。

今回の場合これが僕のやりたかったことですね。

test.rb
array = [1,2,3]
ans = []

array.each do |a|
  if a >= 1
    ans << a
    break
  end
end

p ans

この様にreturnではなくbreakに書き換えてあげると
スクリーンショット 2020-07-28 13.12.16.png

望んでいた[1]がえられました。
条件に該当した時点で、each処理のみを終わらせてくれた、という期待していた挙動になっています。

nextについて

実行されてる処理内で、以降の処理を行わず終わらせますが、繰り返し処理自体は続きます

ちょっとわかりづらいので、以下の様にコードを書き換えて実験して見ます。

test.rb
array = [3,2,1]
ans = []
sum = 0

array.each do |a|
  if a >= 2
    ans << a
  end
  sum += 1
end

p sum

if内の条件をa >= 2にしたので、array[2]は1であるためそれのみ条件に非該当になります。
カウンター用にsumを用意しました。

これを実行すると以下の結果になります。

スクリーンショット 2020-07-28 13.20.07.png

sum += 1はif外かつeach内の処理なので、ifに該当してようとしてなかろうと、要素の数だけ繰り替えされます。
今回は要素が3個あるので、「3」と出力されるわけです。

これにnextを追記します。

test.rb
array = [3,2,1]
ans = []
sum = 0

array.each do |a|
  if a >= 2
    ans << a
    next
  end
  sum += 1
end

p sum

結果は以下の通りです。

スクリーンショット 2020-07-28 13.22.20.png

ifに該当した場合、nextによって以降の処理を無視します。
なので3、2の場合はsum += 1が行われません。

ただし、繰り返し処理自体は継続されます。
なので、array[2]が1であり、ifに非該当であった場合はsum += 1が実行されており、結果として1が出力されているわけです。

終わりに

頭でわかってることをプログラムにやってもらう時の指示の出し方についてまだまだ知らないことが多いな〜という印象です。
機械語を理解するのは大事だなと思うわけで、半分趣味にはなってますがアルゴリズムの勉強もしたくてたまんないなという最近です。実際こういう気づきあるし笑

※かなりざっくりした理解で書いているので、間違い等あれば指摘いただけるとありがたいです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away