红宝石块并从块中返回一些东西

时间:2010-05-14 18:08:48

标签: ruby

我使用的是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

4 个答案:

答案 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(它的名称是这样的,因为使用迭代器方法,如eachmap从块返回基本上意味着跳转到循环的下一次迭代。) / 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

更多信息: