从matz ruby​​切换到jruby时出现奇怪的`return`行为

时间:2014-09-18 15:46:26

标签: ruby jruby behavior incompatibility

为什么这个片段:

def dump_dump
    get_dump = lambda do
        return 1 if $n
        $n = true
        module_exec &get_dump
        2
    end
    p get_dump[]
end

Module.new do
    module_exec &method(:dump_dump)
end

在ruby 2.0.0p481中打印2(2014-05-08)[x64-mingw32]
但在Java HotSpot(TM)64位服务器VM上的jruby 1.7.15(1.9.3p392)2014-09-03 82b5cc3中1  1.7.0_67-b01 + jit [Windows 8-amd64]?

我想了解这个问题。

UPD:应该在某处报道吗?

2 个答案:

答案 0 :(得分:2)

我总是认为块内的return是未定义的行为。您可以使用next吗?

例如,Rubinius也有这个问题,但更为明确:

[1].map(&lambda { |n| return -1 })
LocalJumpError: unexpected return

当然,使用next会产生预期的结果:

rbx-head :003 > [1].map(&lambda { |n| next -1 })
 => [-1] 

故事的寓意是return是为方法定义的,而Proc和lambdas不是方法。如果您希望停止阻止调用,则nextbreak是要使用的关键字。

我无法从官方Ruby规范中找到有关return行为的任何文档,但rubyspec确实有验证return导致调用方法的测试回来。

https://github.com/rubyspec/rubyspec/blob/master/language/return_spec.rb#L184

答案 1 :(得分:0)

lambda中的'return'应该从lambda返回而不是从方法返回。 在这个棘手的情况下,看起来jruby不尊重内部lambda,而是一直返回到第一个lambda调用。

起初我以为它可能是由lambda中的lambda调用引起的,但现在我认为这是一个与块转换相关的问题,在将示例简化为此之后:

Module.new do
  test = lambda do
    return
  end
  module_exec &test
  puts 'after'
end

这里只有mri打印'after',而jruby打印没有。

...但如果我们不做lambda来阻止转换(& test):

Module.new do
  test = lambda do
    return
  end
  module_exec { test[] }
  puts 'after'
end

mri和jruby都打印'之后'......