我需要使用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
如果我使用return
替换了我的块中的next
,我确定我可以在1.8.7中使用它,但是next square(n) if n < 5
在1.8.6中导致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
,它也可以在那里工作。
答案 0 :(得分:1)
在评论后修改 有关详细信息,请参阅此post。
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
def a
block = lambda { | n|
return square(n) if n < 5
cube(n)
}
f = Foo.new
puts f.call_block(3, &block) # returns 125
puts "Never makes it here in 1.8.7"
puts f.call_block(5, &block) # returns 9 in 1.8.6, returns nothing in 1.8.7
end
a
此代码不会产生任何结果,因为它会在puts语句之外返回。
procs和lambdas的工作方式在1.9中有所改变。这有助于解释最新进展。
<强>原始强>
我重构了你的代码,它在所有3个vm下运行。有趣的是,你的代码确实在1.9下执行而没有例外。
class Foo
def square(n)
n ** 2
end
def cube(n)
n ** 3
end
def call_block(*args, &block)
block.call(self, *args)
end
end
block = lambda { |obj, n|
return obj.square(n) if n < 5
obj.cube(n)
}
f = Foo.new
puts f.call_block(5, &block) # returns 125
puts f.call_block(3, &block) # returns 9
此post可能具有一定的洞察力。