Используя 'возврат' в блоке Ruby

Я пытаюсь использовать Ruby 1.9.1 для встроенного языка сценариев, так, чтобы код "конечного пользователя" был написан в блоке Ruby. Одна проблема с этим - то, что я хотел бы, чтобы пользователи смогли использовать ключевое слово 'возврата' в блоках, таким образом, они не должны волноваться о неявных возвращаемых значениях. Принимая это во внимание, это - вид вещи, которую я хотел бы смочь сделать:

def thing(*args, &block)
  value = block.call
  puts "value=#{value}"
end

thing {
  return 6 * 7
}

Если я использую 'возврат' в вышеупомянутом примере, я получаю LocalJumpError. Я знаю, что это вызвано тем, что рассматриваемым блоком является Proc и не лямбда. Код работает, если бы я удаляю 'возврат', но я действительно предпочел бы мочь использовать 'возврат' в этом сценарии. Действительно ли это возможно? Я попытался преобразовать блок в лямбду, но результатом является то же.

81
задан Mohsen Nosratinia 8 May 2015 в 14:16
поделиться

4 ответа

Вы смотрите не с той точки зрения. Это проблема штуки , а не лямбда.

def thing(*args, &block)
  block.call.tap do |value|
    puts "value=#{value}"
  end
end

thing {
  6 * 7
}
3
ответ дан 24 November 2019 в 09:33
поделиться

Просто используйте 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 был вызван
163
ответ дан 24 November 2019 в 09:33
поделиться

Вы не можете сделать это в 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
# ...
18
ответ дан 24 November 2019 в 09:33
поделиться

Где вызывается вещь? Вы внутри класса?

Вы можете использовать что-то вроде этого:

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
1
ответ дан 24 November 2019 в 09:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: