Я пытаюсь использовать Ruby 1.9.1 для встроенного языка сценариев, так, чтобы код "конечного пользователя" был написан в блоке Ruby. Одна проблема с этим - то, что я хотел бы, чтобы пользователи смогли использовать ключевое слово 'возврата' в блоках, таким образом, они не должны волноваться о неявных возвращаемых значениях. Принимая это во внимание, это - вид вещи, которую я хотел бы смочь сделать:
def thing(*args, &block)
value = block.call
puts "value=#{value}"
end
thing {
return 6 * 7
}
Если я использую 'возврат' в вышеупомянутом примере, я получаю LocalJumpError. Я знаю, что это вызвано тем, что рассматриваемым блоком является Proc и не лямбда. Код работает, если бы я удаляю 'возврат', но я действительно предпочел бы мочь использовать 'возврат' в этом сценарии. Действительно ли это возможно? Я попытался преобразовать блок в лямбду, но результатом является то же.
Вы смотрите не с той точки зрения.
Это проблема штуки
, а не лямбда.
def thing(*args, &block)
block.call.tap do |value|
puts "value=#{value}"
end
end
thing {
6 * 7
}
Просто используйте next
в этом контексте:
$ irb
irb(main):001:0> def thing(*args, &block)
irb(main):002:1> value = block.call
irb(main):003:1> puts "value=#{value}"
irb(main):004:1> end
=> nil
irb(main):005:0>
irb(main):006:0* thing {
irb(main):007:1* return 6 * 7
irb(main):008:1> }
LocalJumpError: unexpected return
from (irb):7:in `block in irb_binding'
from (irb):2:in `call'
from (irb):2:in `thing'
from (irb):6
from /home/mirko/.rvm/rubies/ruby-1.9.1-p378/bin/irb:15:in `<main>'
irb(main):009:0> thing { break 6 * 7 }
=> 42
irb(main):011:0> thing { next 6 * 7 }
value=42
=> nil
return
всегда возвращается из метода, но если вы протестируете этот фрагмент в irb у вас нет метода, поэтому у вас есть LocalJumpError
break
возвращает значение из блока и завершает его вызов. Если ваш блок был вызван с помощью yield
или .call
, то break
также прерывается из этого итератора next
возвращает значение из блока и завершает его вызов. Если ваш блок был вызван с помощью yield
или .call
, то next
возвращает значение в строку, где yield
был вызван Вы не можете сделать это в Ruby.
Ключевое слово return
всегда возвращает из метода или лямбда в текущем контексте. В блоках он будет возвращаться из метода, в котором было определено закрытие . Невозможно заставить вернуться из метода , вызывающего , или лямбда-выражения.
Rubyspec демонстрирует, что это действительно правильное поведение для Ruby (по общему признанию, не реальная реализация, но нацелена на полную совместимость с C Ruby):
describe "The return keyword" do
# ...
describe "within a block" do
# ...
it "causes the method that lexically encloses the block to return" do
# ...
it "returns from the lexically enclosing method even in case of chained calls" do
# ...
Где вызывается вещь? Вы внутри класса?
Вы можете использовать что-то вроде этого:
class MyThing
def ret b
@retval = b
end
def thing(*args, &block)
implicit = block.call
value = @retval || implicit
puts "value=#{value}"
end
def example1
thing do
ret 5 * 6
4
end
end
def example2
thing do
5 * 6
end
end
end