在 Ruby 1.8 中,返回 lambda 内的 for 循环会崩溃

发布于 2024-07-26 08:08:57 字数 514 浏览 4 评论 0原文

在 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

In Ruby 1.8 (my version is 1.8.7-72), this code:

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

crashes with a 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

Why does it do this? However, it seems to run fine on my version of Ruby 1.9.

Edit: it's not just the returning inside a lambda; the following runs fine:

foo = lambda do
  return
end
foo.call

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

豆芽 2024-08-02 08:08:57

发生的情况是 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,因为迭代器将返回 1foo[] + 1 > 因此将返回 2

如果所有这些听起来令人困惑,那么要认识到的主要事情是块内的返回范围仅限于周围的方法,并且如果没有周围的方法,则会引发 LocalJumpError

What's happening is that the for statement in the middle of the lambda is converted internally into a block. In Ruby, return statements inside blocks are scoped to their enclosing method. Consider the following:

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

When running bar, 1 is returned, because the return is scoped to the entire bar method. To return from blocks, you want to use next or break, both of which take parameters. Consider:

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

This break returns you from the block, and blocks any subsequent iterations. In this case, calling bar would return 2, since the iterator will return 1, and foo[] + 1 will therefore return 2.

If all of that sounded confusing, the main thing to realize is that return inside blocks is scoped to a surrounding method, and absent a surrounding method, a LocalJumpError is raised.

安稳善良 2024-08-02 08:08:57

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

you can escape the loop and the rest of the lambda with a throw/catch

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 also takes an optional second paramter, which you can use to return a value.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文