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 中的闭包