如果没有`rescue`用作代码块,那么Ruby的`begin … end`是否会产生意想不到的后果?

我偶尔会看到begin...endruby中使用的begin...end块没有任何rescueelseensure等等之间的陈述。 例如:

 foo = begin whatever = 3 "great" 42 end 

看起来,编码器的意图是使用begin...end块只是因为它的块分组质量(就像begin do )。 就个人而言,我认为这种用法违反了最少惊喜的原则( begin意味着对我的exception处理)。

以这种方式使用begin...end会有任何意想不到的后果吗? begin...end块有任何语义差异(可能在exception处理?),使这种使用危险?

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等)。 与a = 5; c = 6相比,这是唯一的副作用a = 5; c = 6 a = 5; c = 6dup指令,这意味着您的方法的堆栈大小将增加1个插槽。 但这并不是特别重要,因为它只有在解释器在这个特定方法中时才有任何效果,并且堆栈的内存无论如何都是预先保留的,所以它只意味着堆栈指针将比其它方式减少1。 所以基本上没有变化。 随着优化打开,即使dup也可能会消失。