在Ruby 1.8中为lambda内部循环返回内部崩溃

在Ruby 1.8中为lambda内部循环返回内部崩溃,ruby,lambda,for-loop,return,Ruby,Lambda,For Loop,Return,在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' fro

在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

所发生的事情是lambda中间的for语句被内部转换成块。在Ruby中,块内的返回语句的作用域是它们的封闭方法。考虑以下事项:

def bar
  foo = lambda do
    for j in 1..2
      return j
    end
  end
  foo[]
end
p bar
运行
bar
时,将返回
1
,因为
返回
的范围是整个
bar
方法。要从块返回,需要使用
next
break
,这两种方法都采用参数。考虑:

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的其余部分

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
还需要一个可选的第二个参数,您可以使用它返回一个值。

为什么它不能作用于lambda呢?我不能简单地跳出循环,因为在我最初的场景中,在for循环之后有一些代码我需要学习。你可以尝试使用真实的方法,而不是lambda.dam。Ruby 1.8不允许从通过define_方法定义的方法中从进程内部返回。我认为这是一个模拟返回的非常重要的解决方案。模拟返回没有太多其他选项(其他选项是exceptions和callcc)。我怀疑这是最轻的重量。最好的解决方案可能只是使用一种方法,但如果您需要关闭的范围不适合这样做,那么这可能会很尴尬。这就是为什么1.9允许您从lambda返回是很好的。我在回答中添加了一种在Ruby 1.8中模拟Ruby 1.9 lambda的方法,这将比throw/catch.Hmm更轻量级。我试过那种方法,但没有完全奏效。我肯定是生锈了。Ruby 1.8已经过时了,无法使用:(我恢复了我的更改。