Ruby 中的 Proc 对象内的 return 到哪个级别?
To which level returns a return inside a Proc Object in Ruby?
据我了解,return
在 Proc
中终止了当前方法。所以在下面的例子中我希望看到:
a1 > b1 > 过程 > a2。但实际上它从来没有达到a2,为什么?
def a
puts "a1"
l = Proc.new {puts "proc"; return}
b l
puts "a2"
end
def b x
puts "b1"
x.call
puts "b2"
end
a
作为一般规则,return
总是 returns 来自 最近的词法封闭方法定义表达式 .
在这种情况下,最接近词法封闭的方法定义表达式是 def a
,因此,return
returns 来自 a
.
在这种情况下,return
在块内实际上并不重要。一般规则是通用的,所以无论 return
出现在哪里,它都适用。
但是,如果我们更具体地查看块,我们会发现它仍然有意义:在块中,局部变量是词法捕获的,self
是词法捕获的,所以 return
也有词法行为。它是一个通用的属性块,如果你想了解一个块中发生了什么,你只需要从词法上向外看。
如果我们更具体一些,首先从一般规则到块,现在从块到 Proc
s,行为仍然有意义:Proc
本质上是一个具体化的块,因此 Proc
表现得像块是有意义的。
不过, 有一些例外一般规则,其中一个重要的例外是 lambdas。在 Ruby 中谈论 lambda 总是有点奇怪,因为 lambda 是 Proc
,但它们的行为与 Proc
不同。 IMO,lambda 应该在 Proc
旁边有一个单独的 class。由于 lambda 是 Proc
s,所以谈论 lambdas 和 Proc
s 之间的区别是很奇怪的,它们不是 lambdas(它们没有标准化的名称,因此也被混淆地称为 Proc
s).
lambda 的行为不同于非 lambda 的行为 Proc
在两个方面,其中一个与您的问题相关:
- 非 lambda 中的参数绑定
Proc
s 与块中的参数绑定具有相同的语义,而 lambda 中的参数绑定与消息发送/方法调用中的参数绑定具有相同的语义。
- 在非 lambda
Proc
s 中,return
returns 来自最接近的词法封闭方法定义表达式,就像在块中一样,而在 lambda 中,return
returns 来自 lambda 本身,就像方法中的 return
。
因此,在这两个方面,非 lambda Proc
表现得像块,而 lambda 表现得像方法。我是这样记的:“Proc
”与“block”押韵,“lambda”和“method”都是希腊语。
您可能知道,有些方法也会改变传递给它们的块的行为。例如。 instance_eval
和 instance_exec
改变了 self
的值,而 define_method
实际上确实改变了 return
.
的行为
但是由于你没有问一般的块,也没有具体问lambdas,而且你的问题中没有反射方法,所以一般规则仍然适用于非lambda Proc
就像您的问题中显示的那样:return
returns 来自最接近的词法封闭方法定义表达式。
据我了解,return
在 Proc
中终止了当前方法。所以在下面的例子中我希望看到:
a1 > b1 > 过程 > a2。但实际上它从来没有达到a2,为什么?
def a
puts "a1"
l = Proc.new {puts "proc"; return}
b l
puts "a2"
end
def b x
puts "b1"
x.call
puts "b2"
end
a
作为一般规则,return
总是 returns 来自 最近的词法封闭方法定义表达式 .
在这种情况下,最接近词法封闭的方法定义表达式是 def a
,因此,return
returns 来自 a
.
在这种情况下,return
在块内实际上并不重要。一般规则是通用的,所以无论 return
出现在哪里,它都适用。
但是,如果我们更具体地查看块,我们会发现它仍然有意义:在块中,局部变量是词法捕获的,self
是词法捕获的,所以 return
也有词法行为。它是一个通用的属性块,如果你想了解一个块中发生了什么,你只需要从词法上向外看。
如果我们更具体一些,首先从一般规则到块,现在从块到 Proc
s,行为仍然有意义:Proc
本质上是一个具体化的块,因此 Proc
表现得像块是有意义的。
不过, 有一些例外一般规则,其中一个重要的例外是 lambdas。在 Ruby 中谈论 lambda 总是有点奇怪,因为 lambda 是 Proc
,但它们的行为与 Proc
不同。 IMO,lambda 应该在 Proc
旁边有一个单独的 class。由于 lambda 是 Proc
s,所以谈论 lambdas 和 Proc
s 之间的区别是很奇怪的,它们不是 lambdas(它们没有标准化的名称,因此也被混淆地称为 Proc
s).
lambda 的行为不同于非 lambda 的行为 Proc
在两个方面,其中一个与您的问题相关:
- 非 lambda 中的参数绑定
Proc
s 与块中的参数绑定具有相同的语义,而 lambda 中的参数绑定与消息发送/方法调用中的参数绑定具有相同的语义。 - 在非 lambda
Proc
s 中,return
returns 来自最接近的词法封闭方法定义表达式,就像在块中一样,而在 lambda 中,return
returns 来自 lambda 本身,就像方法中的return
。
因此,在这两个方面,非 lambda Proc
表现得像块,而 lambda 表现得像方法。我是这样记的:“Proc
”与“block”押韵,“lambda”和“method”都是希腊语。
您可能知道,有些方法也会改变传递给它们的块的行为。例如。 instance_eval
和 instance_exec
改变了 self
的值,而 define_method
实际上确实改变了 return
.
但是由于你没有问一般的块,也没有具体问lambdas,而且你的问题中没有反射方法,所以一般规则仍然适用于非lambda Proc
就像您的问题中显示的那样:return
returns 来自最接近的词法封闭方法定义表达式。