【问题标题】:Returning inside for loop inside lambda crashes in Ruby 1.8在 Ruby 1.8 中返回内部 lambda 内部的 for 循环崩溃
【发布时间】:2010-11-08 04:33:08
【问题描述】:

在 Ruby 1.8(我的版本是 1.8.7-72)中,这段代码:

foo = lambda do
  for j in 1..2
    return
  end
end
foo.call

使用LocalJumpError 崩溃:

test2.rb:3: unexpected return (LocalJumpError)
    from test2.rb:2:in `each'
    from test2.rb:2
    from test2.rb:6:in `call'
    from test2.rb:6

为什么要这样做?但是,它似乎在我的 Ruby 1.9 版本上运行良好。

编辑:这不仅仅是 lambda 内部的返回;以下运行良好:

foo = lambda do
  return
end
foo.call

【问题讨论】:

    标签: ruby lambda for-loop return


    【解决方案1】:

    发生的事情是 lambda 中间的 for 语句在内部转换为块。在 Ruby 中,块内的 return 语句的作用域是它们的封闭方法。考虑以下几点:

    def bar
      foo = lambda do
        for j in 1..2
          return j
        end
      end
      foo[]
    end
    p bar
    

    运行bar 时,会返回1,因为return 的作用域是整个bar 方法。要从块中返回,您需要使用nextbreak,它们都带有参数。考虑:

    def bar
      foo = lambda do
        for j in 1..2
          break j
        end
      end
      foo[] + 1
    end
    p bar
    

    此中断将您从块中返回,并阻止任何后续迭代。在这种情况下,调用bar 将返回2,因为迭代器将返回1,因此foo[] + 1 将返回2

    如果所有这些听起来令人困惑,那么要意识到的主要事情是,块内的 return 被限定为一个周围的方法,如果没有一个周围的方法,则会引发 LocalJumpError

    【讨论】:

    • 为什么不能改为 lambda?我不能简单地跳出循环,因为在我原来的场景中,我需要跳过 for 循环之后的代码
    • 您可以尝试使用真正的方法,而不是 lambda。
    • 该死的。 Ruby 1.8 不允许从通过define_method 定义的方法内部从proc 内部返回。从头开始。
    【解决方案2】:

    您可以使用 throw/catch 来逃避循环和 lambda 的其余部分

    foo = lambda do 
            catch(:escape) do
              for j in 1..2
                throw :escape
              end
              # other code that won't get run
            end # catch(:escape)
          end # lambda
    

    throw 还带有一个可选的第二个参数,您可以使用它来返回一个值。

    【讨论】:

    • 我认为这是一个非常重量级的模拟回报解决方案。
    • 没有很多其他选项可以模拟返回(其他选项是异常和 callcc)。我怀疑选择它是最轻的。最好的解决方案可能只是使用一种方法,但如果您需要关闭的范围不适合这样做,这可能会很尴尬。这就是为什么 1.9 让你从 lambda 中返回很好的原因。
    • 我在回答中添加了一种在 Ruby 1.8 中模拟 Ruby 1.9 lambdas 的方法,这将比 throw/catch 更轻量级。
    • 嗯。我尝试了这种方法,但我并没有让它发挥作用。毫无疑问,我生疏了。
    • 不。 Ruby 1.8 已经过时了,它不会工作:(我恢复了我的改变。
    猜你喜欢
    • 1970-01-01
    • 2015-01-09
    • 2014-09-16
    • 1970-01-01
    • 2015-03-21
    • 2014-07-16
    • 2021-05-06
    • 1970-01-01
    • 2020-07-18
    相关资源
    最近更新 更多