4

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,但我想理解该错误也将解决该问题。

提前感谢您的澄清

4

2 回答 2

4

这是我对相关问题的回答。它谈到了一些关于 lambda vs proc 和 LocalJumpErrors 的内容。

在 proc 中,是从 proc 的词法return范围返回的特殊语法,而不是 proc 本身。所以它试图从已经退出的 中返回。procBuilder

有几种方法可以解决这个问题:

  1. 根本不要使用return。Ruby 会自行将控制权返回给 proc 的调用者。
  2. 更改proclambda,其行为符合您的预期。Lambda 的行为类似于方法;procs 就像块一样。

至于你期望的错误,你不应该得到那个。procBuilder返回一个包含消息变量的过程。您不需要 proc 本身的任何参数。

编辑:回答您的其他问题。proc 是一个闭包。它“捕获”了消息变量( 中的局部变量procBuilder),该变量在创建 proc 时就在范围内。proc 现在可以在你的程序中漫游,其中隐藏了 message 变量,当你调用它时可以打印出来。唯一的麻烦是 return 语句,它有额外的要求,它的词法范围仍然是“活的”。

这一切的原因是这种行为在块中确实很有帮助。在这种情况下,它根本没有帮助,所以你应该只使用 a lambda,其中 return 意味着一些不那么疯狂的东西。

一个非常棒的关于 ruby​​ 闭包的教程:http: //innig.net/software/ruby/closures-in-ruby.rb

于 2011-11-17T06:19:44.593 回答
0

proc 和方法或 lambda 之间的一个重要区别是它们处理 return 语句的方式。如果一个方法定义在另一个方法内部,那么内部方法中的return语句只从内部方法本身退出,然后外部方法继续执行。在 lambda 中定义 lambda、在方法中定义 lambda 或在 lambda 中定义方法也是如此。但是,当在方法中定义 proc 时,return 语句将从 proc 以及外部(封闭)方法中退出。例子:

def meditate
    puts "Adjusting posture…"
    p = Proc.new { puts "Ringing bell…"; return }
    p.call
    puts "Sitting still…"  # This is not executed
end

meditate

Output:
Adjusting posture…
Ringing bell…

注意方法的最后一行没有执行,因为 proc 中的 return 语句已经从 proc 和封闭方法中退出。

如果我们定义一个没有封闭(外部)方法的 proc 并使用 return 语句,它将抛出 LocalJumpError。

p = Proc.new { puts "Ringing bell…"; return }
p.call
Output:
Ringing bell…
LocalJumpError: unexpected return

发生这种情况是因为在 proc 中到达 return 语句时,它不是从调用它的上下文返回,而是从定义它(proc)的范围返回。在以下示例中,发生 LocalJumpError 是因为 proc 试图从定义它的顶级环境返回。

def meditate p
    puts "Adjusting posture…"
    p.call
    puts "Sitting still…"  # This is not executed
end

p = Proc.new { puts "Ringing bell…"; return }

meditate p
Output:
Adjusting posture…
Ringing bell…
LocalJumpError: unexpected return

通常,在 proc 中使用 return 语句不是一个好主意。Procs 通常在方法之间传递,如果定义 proc 的方法已经返回,它将抛出异常。在下面的示例中,我们可以删除 return 语句。但是,在某些情况下,我们实际上需要返回一些东西。在后者中,最好使用 lambda 而不是 proc。稍后我们将看到 lambda 以不同的方式处理返回语句,更像是方法。

下面是另一个涉及 return 语句的场景:

def zafu_factory
    # This method will return the following proc implicitly
    Proc.new { puts "Round black zafu"; return }
end

def meditate
    puts "Adjusting posture…"
    p = zafu_factory
    p.call
    puts "Sitting still…"  # This is not executed
end

meditate
Output:
Adjusting posture…
Round black zafu
LocalJumpError: unexpected return

刚刚发生了什么?zafu_factory 方法创建并隐式返回一个 proc。然后,proc 由 meditate 方法调用,当到达 proc 中的 return 语句时,它尝试从定义它的上下文(zafu_factory 方法)返回。但是,zafu_factory 已经返回了 proc,并且方法每次调用只能返回一次。换句话说,由于 zafu_factory 方法在调用 proc 并尝试第二次返回时已经返回,因此引发了异常。

在这篇关于Procs 和 Lambdas的博客文章中查看更多信息:Ruby 中的闭包

于 2016-05-17T22:10:41.480 回答