[英]Are there unintended consequences of Ruby's `begin … end` without `rescue` used as a code block?
我偶尔会看到ruby中使用的begin...end
块,而没有进行任何rescue
, else
, ensure
等语句之间。 例如:
foo = begin
whatever = 3
"great"
42
end
看来,编码器的意图是仅出于其块分组质量而使用begin...end
块(就好像begin
是do
)。 我个人认为这种用法违反了最少惊讶的原则( begin
对我意味着异常处理)。
以这种方式使用begin...end
有任何意外的后果吗? begin...end
块是否有任何语义差异(可能在异常处理中?),使这种用法很危险?
Ruby的语法令人难以置信,如果在这里等待等待,我就不会感到惊讶。
如果我想给变量赋值,但有时我必须先计算要赋值,我有时会用到它。 这样可以使代码更加整洁。 我认为这是用户的偏爱。 基本上您是在说:我为foo分配了一些东西,但是为了获得所需的值,我首先需要做一些事情。 做备忘录时特别有用,因此
if @cache.nil?
do_something!
@cache = read_value
end
你可以做
@cache ||= begin
do_something!
read_value
end
您在这里利用的是Ruby解释器有一个堆栈,每个表达式通常会将某些内容压入堆栈或从堆栈中取出内容。 分配只是从堆栈中取出最后一个东西并分配它(在这种情况下,这是开始/结束的最后一行)。 很多时候了解这一点(Ruby中的堆栈方法)可能会很有用。
我认为它不会给您带来什么意外的惊喜,我认为您是否愿意使用它都是用户的首选。
通过查看它在Ruby MRI 1.9中生成的字节码指令,您可以看到它没有做任何意外的事情:
RubyVM::InstructionSequence::compile("c = begin; a = 5; 6; end").to_a
[:trace, 1],
[:trace, 1],
[:putobject, 5],
[:setlocal, 2],
[:trace, 1],
[:putobject, 6],
[:dup],
[:setlocal, 3],
[:leave]
跟踪仅用于堆栈跟踪,您可以忽略它。 Dup复制堆栈中的最后一个项目。 在此示例中,局部变量a
的数量为2
,局部变量c
的数量为3
(因此putobject, 2
将分配给变量a
, putobject, 2
)。 与a = 5; c = 6
相比,其唯一的副作用a = 5; c = 6
a = 5; c = 6
是dup
指令,这意味着方法的堆栈大小将增加1个插槽。 但这并不是特别重要,因为它仅在解释器位于此特定方法内部时才起作用,并且无论如何都将为堆栈保留内存,因此这仅意味着堆栈指针将比原来减少1。 因此,基本上没有任何变化。 启用优化后,即使dup
也可能消失。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.