我使用的是ruby 1.8.7。
p = lambda { return 10;}
def lab(block)
puts 'before'
puts block.call
puts 'after'
end
lab p
以上代码输出
before
10
after
我将相同的代码重构为此
def lab(&block)
puts 'before'
puts block.call
puts 'after'
end
lab { return 10; }
现在我收到LocalJumpError:意外返回。
对我而言,两个代码都在做同样的事情。是的,在第一种情况下,我通过了一个过程,在第二种情况下,我正在通过一个块。但是& block将那些块转换为proc。因此proc.call应该表现相同。
是的,我看过这篇文章Using 'return' in a Ruby block
答案 0 :(得分:8)
当您使用&传递块时,您将其转换为proc。重要的是一个proc和一个lambda是不同的(lambda实际上是proc的子类),特别是它们如何处理return。
所以你的重构代码实际上相当于:
p = Proc.new { return 10;}
def lab(block)
puts 'before'
puts block.call
puts 'after'
end
lab p
也会生成LocalJumpError。
原因如下:proc的返回从其词法范围返回,但lambda返回其执行范围。因此,当lambda返回lab
时,传递给它的proc返回到声明它的外部作用域。本地跳转错误意味着无处可去,因为没有封闭功能。
The Ruby Programming Language说得最好:
Procs具有类似块的行为,lambdas具有类似方法的行为
您只需要跟踪您在哪里使用的内容。正如其他人所建议的那样,您需要做的只是从您的区块中删除return
,事情将按预期运行。
答案 1 :(得分:5)
return
将从块所在的方法返回,而不是从块中返回。要从块中返回,请使用next
(它的名称是这样的,因为使用迭代器方法,如each
和map
从块返回基本上意味着跳转到循环的下一次迭代。) / p>
请注意,当返回值是块中最后一个已计算的表达式时,根本不需要任何类型的return语句,即lab { 10 }
将执行相同的操作。
答案 2 :(得分:0)
{}
块包含给定它的上下文,因此return
尝试从行lab { return 10; }
返回。你可以通过将该行放在一个方法中来实际完成这项工作(有时甚至是以一种有用的方式),然后返回该方法(即“不打印”)。
要将10
返回block.call
,请省略return
(或替换next
)。
答案 3 :(得分:0)
我认为你只需要在传递之前取消引用该块:
foo = lambda { return 10 }
def trace_block(&fn)
puts 'before calling fn'
puts fn.call
puts 'after caling fn'
end
trace_block(&foo)
输出:
before calling fn
10
after caling fn
更多信息: