Ruby Lambda 与 Proc LocalJumpError
Ruby 和 StackOverflow 新手在这里使用 Ruby 进行工作,并遇到了我的第一个主要障碍。我真的很难理解 Procs 和 Lambdas。这是我正在使用的代码。
def procBuilder(message)
Proc.new{ puts message; return}
end
def test
puts "entering method"
p = procBuilder("entering proc")
p.call
puts "exit method"
end
test
按照设计,这是为了抛出 LocalJumpError,但我不明白为什么。如果我不得不猜测这是做什么的,我猜它最初会在 p = procBuilder("entering proc") 运行时打印“entering proc”,然后在 p.call 上抛出错误,因为 p.call 没有传递任何字符串,但显然我错过了这两行之间发生的一些关键事情。我也不完全理解为什么这适用于 lambda 而不是 proc,但我想理解错误也能解决该问题。
预先感谢您的澄清
Ruby and StackOverflow newb here working my way through Ruby and ran into my first major roadblock. I'm having a really hard time wrapping my head around Procs and Lambdas. Here is the code I'm working with.
def procBuilder(message)
Proc.new{ puts message; return}
end
def test
puts "entering method"
p = procBuilder("entering proc")
p.call
puts "exit method"
end
test
By design, this is to throw a LocalJumpError, but I don't rightly understand why. If I had to guess what this did, I would guess it would initially print "entering proc" upon p = procBuilder("entering proc") running then throw an error on p.call as there is no string being passed by p.call, but clearly I'm missing something critical that is occurring between those 2 lines. I also don't completely understand why this works with a lambda rather than a proc but I imagine understanding the error will resolve that issue as well.
Thanks in advance for the clarification
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是我对相关问题给出的答案。它讨论了一些关于 lambda 与 proc 和 LocalJumpErrors 的内容。
在过程中,
return
是一段特殊的语法,它从过程的词法范围返回,而不是过程本身。因此它试图从已经退出的 procBuilder 中返回。有几种方法可以解决此问题:
return
。 Ruby 将自行将控制权返回给 proc 的调用者。proc
更改为lambda
,其行为符合您的预期。 Lambda 的行为类似于方法;过程就像块一样。至于您预期的错误,您不应该得到它。
procBuilder
返回包含消息变量的过程。您不需要过程本身的任何参数。编辑:回答您的附加问题。该过程是一个闭包。它“捕获”了消息变量(procBuilder 中的局部变量),该变量在创建 proc 时处于作用域内。现在,proc 可以在您的程序中漫游,消息变量隐藏在其中,准备在您调用它时打印。唯一的麻烦是 return 语句,它有一个额外的要求,即词法范围仍然是“活动的”。
这一切的原因是这种行为在区块中确实很有帮助。在这种情况下,它根本没有帮助,所以您应该只使用 lambda ,其中 return 意味着不那么疯狂。
关于 ruby 中闭包的非常棒的教程: http://innig.net/software /ruby/closures-in-ruby.rb
Here's an answer I gave to a related question. It talks a bit about lambda vs proc and LocalJumpErrors.
In a proc,
return
is a special piece of syntax that returns from the lexical scope of the proc, not the proc itself. So it's trying to return out ofprocBuilder
, which has already exited.There are a couple ways to fix this:
return
at all. Ruby will return control to proc's caller all on its own.proc
tolambda
, which behaves the way you expect. Lambdas act like methods; procs act like blocks.As for the error you're expecting, you shouldn't get that.
procBuilder
returns a proc that encloses the message variable. You don't need any arguments to the proc itself.Edit: answering your additional question. The proc is a closure. It has "captured" the message variable (a local variable in
procBuilder
), which was in scope when the proc was created. The proc now can wander through your program with the message variable hidden inside of it, ready to be printed when you call it. The only trouble is the return statement, which has the additional requirement that it the lexical scope still be "live".The reason for all this is that this behavior is really helpful in blocks. In this case, it's not helpful at all, so you should just use a
lambda
, where return means something less insane.A really great tutorial on closures in ruby: http://innig.net/software/ruby/closures-in-ruby.rb
proc 和方法或 lambda 之间的一个重要区别是它们处理 return 语句的方式。如果一个方法定义在另一个方法内部,则内部方法中的 return 语句仅从内部方法本身退出,然后外部方法继续执行。这同样适用于在 lambda 中定义 lambda、在方法中定义 lambda 或在 lambda 中定义方法。但是,当在方法内定义 proc 时,return 语句将从 proc 以及外部(封闭)方法中退出。示例:
请注意该方法的最后一行没有执行,因为 proc 中的 return 语句已从 proc 和封闭方法中退出。
如果我们定义一个没有封闭(外部)方法的 proc 并使用 return 语句,它将抛出 LocalJumpError。
发生这种情况是因为当在 proc 内到达 return 语句时,它不是从调用它的上下文返回,而是从定义它(proc)的范围返回。在下面的示例中,发生 LocalJumpError 是因为 proc 试图从定义它的顶级环境返回。
通常,在过程中使用 return 语句不是一个好主意。过程通常在方法之间传递,如果定义过程的方法已经返回,它将抛出异常。在下面的示例中,我们可以删除 return 语句。然而,有些情况下我们实际上需要返回一些东西。在后者中,最好使用 lambda 而不是 proc。稍后我们将看到 lambda 以不同的方式处理 return 语句,更像是方法。
下面是另一个涉及 return 语句的场景:
刚刚发生了什么? zafu_factory 方法创建并隐式返回一个过程。然后,该 proc 由 meditate 方法调用,并且当到达 proc 内的 return 语句时,它尝试从定义它的上下文(zafu_factory 方法)返回。但是,zafu_factory 已经返回了 proc,并且方法每次调用时只能返回一次。换句话说,抛出异常是因为当调用proc时zafu_factory方法已经返回并尝试第二次返回。
有关 Proc 和 Lambda 的更多信息,请参阅此博客文章: Ruby 中的闭包
An important difference between a proc and a method or lambda is the way in which they handle the return statement. If a method is defined inside another method, the return statement in the inner method exits only from the inner method itself, then the outer method continues executing. The same goes for defining a lambda within a lambda, a lambda inside a method or a method within a lambda. However, when a proc is defined within a method, the return statement will exit from the proc as well as the outer (enclosing) method. Example:
Notice how the last line of the method was not executed because the return statement within the proc has exited from both the proc and the enclosing method.
If we define a proc without an enclosing (outer) method and use a return statement, it will throw a LocalJumpError.
This happens because when a return statement is reached within a proc, instead of returning from the context where it was called, it returns from the scope on which it (the proc) was defined. In the following example, a LocalJumpError happens because the proc is trying to return from the top-level environment, where it was defined.
Usually, it's not a good idea to use a return statement within a proc. Procs are usually passed around between methods and if the method on which the proc was defined has already returned, it will throw an exception. In the example below we could just remove the return statement. However, there are cases we actually need to return something. In the latter, it's probably best to use a lambda instead of a proc. We will see later that lambdas handle return statements in a different way, more like methods.
Below is another scenario involving return statement:
What just happened? The zafu_factory method created and implicitly returned a proc. Then, the proc was called by the meditate method and when the return statement within the proc was reached, it tried to return from the context on which it was defined (the zafu_factory method). However, zafu_factory already returned the proc and a method can only return once each time it's called. In other words, an exception was thrown because the zafu_factory method had already returned when the proc was called and tried to return a second time.
See more at this blog post about Procs and Lambdas: Closures in Ruby