Code Fix

上級

Proc.new の中で return すると LocalJumpError になることがある

Proc(Proc.newやKernel#proc)の中でreturnを使うと、そのProcを囲んでいたメソッドから抜けようとします。呼び出し時にすでにそのメソッドの外にいる場合(トップレベルで呼んだ場合など)、戻る先が無くLocalJumpErrorになります。同じ書き方でもlambdaは自分自身から抜けるだけなので、この問題は起きません。

エラーメッセージの読み方

main.rb:2:in `block in make_greeter': unexpected return (LocalJumpError)
main.rb
ファイル名
2
行番号 — 実際にクラッシュした行
block in make_greeter
発生場所 — <main> ならトップレベル、メソッド名ならそのメソッドの中
LocalJumpError
例外クラス — 何が起きたか。ここを検索するのが最短です
unexpected return
詳細メッセージ — どの値が問題だったか

このエラーが出る典型パターン

パターン1

 1  def make_greeter
 2    Proc.new { return "hi" }
                  ^
 3  end
 4  
 5  greet = make_greeter
 6  puts greet.call
main.rb:2:in `block in make_greeter': unexpected return (LocalJumpError) from main.rb:6:in `<main>'

Procの中のreturnは、Procを定義したメソッドから抜けようとします。呼び出す時点でそのメソッドはすでに終わっているため、戻り先が無くLocalJumpErrorになります。

直し方: Proc.new { return "hi" }lambda { return "hi" } にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  def make_titler
 2    Proc.new { return "Sir" }
                  ^
 3  end
 4  
 5  greet = make_titler
 6  puts greet.call
main.rb:2:in `block in make_titler': unexpected return (LocalJumpError) from main.rb:6:in `<main>'

lambdaのreturnは自分自身から抜けるだけなので、同じ書き方でもこの問題は起きません。

直し方: Proc.new { return "Sir" }lambda { return "Sir" } にします。

この問題を解いてみる →

パターン3

 1  def make_labeler
 2    Proc.new { return "OK" }
                  ^
 3  end
 4  
 5  greet = make_labeler
 6  puts greet.call
main.rb:2:in `block in make_labeler': unexpected return (LocalJumpError) from main.rb:6:in `<main>'

Proc.newで作った手続きは、生成元のメソッドが生きている間しかreturnを使えません。

直し方: Proc.new { return "OK" }lambda { return "OK" } にします。

この問題を解いてみる →

パターン4

 1  def make_tagger
 2    Proc.new { return "new" }
                  ^
 3  end
 4  
 5  greet = make_tagger
 6  puts greet.call
main.rb:2:in `block in make_tagger': unexpected return (LocalJumpError) from main.rb:6:in `<main>'

生成したProcをメソッドの外に持ち出して後から呼び出す設計では、Proc.newは危険です。

直し方: Proc.new { return "new" }lambda { return "new" } にします。

この問題を解いてみる →

パターン5

 1  def make_marker
 2    Proc.new { return "done" }
                   ^
 3  end
 4  
 5  greet = make_marker
 6  puts greet.call
main.rb:2:in `block in make_marker': unexpected return (LocalJumpError) from main.rb:6:in `<main>'

戻り値だけが欲しい単純な処理を書きたい場合、無名関数はProcではなくlambdaを使うのが安全です。

直し方: Proc.new { return "done" }lambda { return "done" } にします。

この問題を解いてみる →

よくある誤解

「Procとlambdaはどちらも無名関数だから、returnの挙動も同じはず」という思い込みは誤りです。lambdaのreturnはlambda自身から抜けるだけですが、Procのreturnは定義時に囲んでいたメソッドごと抜けようとするため、状況によってはLocalJumpErrorになります。

まとめ

Proc.new の中で return すると LocalJumpError になることがあるは上級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)