我需要允许在一个类的作用域内定义和调用块,使用instance_exec
(通过Rails 2.3.2)。但是,其中一些块在某些情况下需要提前返回,这给我带来了一个问题。
我的应用程序是使用Ruby 1.8.6构建的,但我也需要让它在1.8.7上运行。在两个版本之间,似乎从lambda内部返回的能力被删除了。下面的代码在1.8.6中工作,但在1.8.7中抛出LocalJumpError
(意外返回):
class Foo
def square(n)
n ** 2
end
def cube(n)
n ** 3
end
def call_block(*args, &block)
instance_exec *args, &block
end
end
block = lambda { |n|
return square(n) if n < 5
cube(n)
}
f = Foo.new
f.call_block(5, &block) # returns 125
f.call_block(3, &block) # returns 9 in 1.8.6, throws a LocalJumpError in 1.8.7
我确定,如果我用next
替换块中的return
,我可以在1.8.7中让它工作,但在1.8.6中,next square(n) if n < 5
会导致nil
。
有什么办法可以让它在1.8.6和1.8.7中都工作吗?我知道我可以重组我的块来使用分支而不是提前返回,但是有些块更复杂,并且有多种情况需要提前返回。
另外,如果我想让我的代码在ruby 1.9中运行,这会进一步改变吗?
**编辑:**我发现它在1.8.6而不是1.8.7中工作的原因是1.8.7在C源代码中定义了自己的instance_exec
,而1.8.6使用Rails的实现。如果我用Rails的版本覆盖1.8.7中的instance_exec
,它也能工作。
1条答案
按热度按时间qmb5sa221#
评论后编辑详情请参见此post。
这段代码没有任何结果,因为它在puts语句之外返回。
procs和lambdas的工作方式在1.9中改变了。这有助于解释发生了什么。
原件
我重构了你的代码,它在所有3个虚拟机下工作。有趣的是,您的代码在1.9下执行时没有异常。
post可能会有一些见解。