2013-07-23 2 views
31

В чем проблема с этим кодом Ruby 2.0?Неожиданное возвращение (LocalJumpError)

p (1..8).collect{|denom| 
    (1...denom).collect{|num| 
     r = Rational(num, denom) 
     if r > Rational(1, 3) and r < Rational(1, 2) 
      return 1 
     else 
      return 0 
     end 
    } 
}.flatten 

Ошибка block (2 levels) in <main>': unexpected return (LocalJumpError). Я хочу создать плоский список, содержащий n единицы (и остальные нули), где n - количество рациональных чисел с знаменателями ниже 8, которые находятся между 1/3 и 1/2. (it's a Project Euler problem). Поэтому я пытаюсь вернуться из внутреннего блока.

+2

Не используйте 'return' в блоке. Просто удалите оба 'return', и ваш код будет в порядке. – oldergod

ответ

37

Вы не можете return внутри блока в рубине *. Последнее утверждение становится возвращаемым значением, так что вы можете просто удалить возвращаемое значение в вашем случае:

p (1..8).collect{|denom| 
    (1...denom).collect{|num| 
     r = Rational(num, denom) 
     if r > Rational(1, 3) and r < Rational(1, 2) 
      1 
     else 
      0 
     end 
    } 
}.flatten 

*: Вы можете внутри lambda блоков: lambda { return "foo" }.call # => "foo". Это связано с определением области обзора и всего этого, и это одно из основных различий между блоками lambda и proc блоков. «Нормальные» блоки, которые вы передаете методам, больше похожи на блоки proc.

+55

Вы * можете * использовать 'return' внутри блока в Ruby. Он будет возвращен из прилагаемого метода. В этом случае метод * * не содержит *, то есть *, почему есть ошибка, это * не *, потому что 'return' в блоке является незаконным. –

+0

@ JörgWMittag Вы правы, я упрощал. 'return' возвращает для ближайшего метода * или *' lambda', который вы внутри. Если вы не внутри, вы получите «LocalJumpError». – henrikhodne

+0

@ JörgWMittag благодарит за это разъясняющее заявление. Ответ был путаным как есть, и вы разъяснили его. Теперь я понимаю, почему эта ошибка возникает в irb легко. –