【问题标题】:ruby block and returning something from block红宝石块并从块中返回一些东西
【发布时间】:2011-02-19 15:48:52
【问题描述】:

我正在使用 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

【问题讨论】:

    标签: ruby


    【解决方案1】:

    当您使用 & 传入块时,您将其转换为 proc。重要的一点是 proc 和 lambda 是不同的(lambda 实际上是 proc 的子类),特别是它们如何处理返回。

    所以你重构的代码实际上相当于:

    p = Proc.new { return 10;}
    def lab(block)
      puts 'before'
      puts block.call
      puts 'after'
    end
    lab p
    

    这也会产生 LocalJumpError。

    原因如下:proc 的 return 从其词法范围返回,但 lambda 返回其执行范围。因此,尽管 lambda 返回到 lab,但传递给它的 proc 返回到声明它的外部作用域。本地跳转错误意味着它无处可去,因为没有封闭函数。

    The Ruby Programming Language 说得最好:

    Procs 具有类似块的行为,而 lambda 具有类似方法的行为

    您只需要跟踪您在哪里使用什么。正如其他人所建议的那样,您只需将return 从您的块中删除,事情就会按预期进行。

    【讨论】:

      【解决方案2】:

      块内的return 将从块所在的方法返回,而不是从块中返回。要从块返回,请使用next(之所以这样命名,是因为使用像eachmap 这样的迭代器方法,从块返回基本上意味着跳转到循环的下一个迭代)。

      请注意,当返回值是块中最后计算的表达式时,您根本不需要任何类型的 return 语句,即lab { 10 } 会做同样的事情。

      【讨论】:

        【解决方案3】:

        {} 块包含给出它的上下文,因此return 尝试从lab { return 10; } 行返回。您实际上可以通过将该行放在一个方法中来完成这项工作(有时甚至以一种有用的方式),然后该方法将返回(即不打印“之后”)。

        要将10 返回到block.call,请省略return(或替换next)。

        【讨论】:

          【解决方案4】:

          我认为你只需要在传递之前取消引用块:

           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
          

          更多信息:

          【讨论】:

          猜你喜欢
          • 2023-03-07
          • 2014-11-15
          • 2011-07-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多