クイズ形式で rubyのジャンプ構文の挙動をおさらいしてみましょう

全問正解した人は自慢して良いと思います。全5問です。

なお、動作環境は ruby 2.5.0 です

問1 Procの中でbreak

実行結果はどうなるでしょう?

def main
  p = Proc.new{|v|
    p v
    break if v >= 5
  }

  1.upto(10, &p) # & は、ブロックの代わりにProcを渡す命令

  p "finished"
end

main

LocalJumpError

解説

  • breakループから抜け出す命令
  • Proc はループではないので例外が発生する

問2 Procの中でnext

実行結果はどうなるでしょう?

def main
  p = Proc.new{|v|
    p v
    next if v >= 5
  }

  1.upto(10, &p)

  p "finished"
end

main

1
2
3
4
5
6
7
8
9
10
finished

解説

  • next は手続きオブジェクトの場合 手続きオブジェクトから脱出する命令
  • 手続きオブジェクトから脱出するが、 upto のループからは脱出しないので、10まで実行される

問3 Procの中でreturn

実行結果はどうなるでしょう?

def main
  p = Proc.new{|v|
    p v
    return if v >= 5
  }

  1.upto(10, &p)
  
  p "finished"
end

main

1
2
3
4
5

解説

  • return は Procの場合手続きオブジェクトの定義をしたメソッドから脱出する命令
  • そのため、 p "finished" は実行されない

問4 外部で定義したProcの中でreturn

実行結果はどうなるでしょう?

def create_proc
  Proc.new{|v|
    p v
    return if v >= 5
  }
end

def main
  p = create_proc
  1.upto(10, &p)
  
  p "finished"
end

main

LocalJumpError

解説

  • return は Procの場合手続きオブジェクトの定義をしたメソッドから脱出する命令
  • しかし、すでに 手続きオブジェクトの定義をしたメソッド が終了している場合、脱出できないので例外となる
  • こういった、既に生成されたメソッドが終了している手続きオブジェクトを orphan(孤児) と呼ぶ

問5 lambdaの中でbreak

実行結果はどうなるでしょう?

def main
  p = lambda {|v|
    p v
    break if v >= 5
  }

  1.upto(10, &p)

  p "finished"
end

main

1
2
3
4
5
6
7
8
9
10
finished

解説

  • lambdaの場合、 next, break, return 全てが 手続きオブジェクトからの脱出の命令になる

まとめ

手続きオブジェクト

Proclambda のように、ブロックをオブジェクトにしたもの

Proc

  • next : 手続きオブジェクトからの脱出
  • return : 手続きオブジェクトを定義したメソッドから脱出
    • ただし、既にメソッドが終了している場合、LocalJumpError
  • break : LocalJumpError

lambda

next, break, return 全てが 手続きオブジェクトからの脱出

感想

lambdaがなんでこんなやっつけな挙動なのか知っている人いたらおしえてください

参考文献