我偶尔会看到在ruby中使用的最终块,没有任何的救援,否则,确保等等.例如:
foo = begin whatever = 3 "great" 42 end
编码器的意图似乎是使用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,[:putobject,5],[:setlocal,2],6],[:dup],3],[:leave]
跟踪只是堆栈跟踪,你可以忽略它. Dup重复堆栈上的最后一个项目.在本示例中,局部变量a的数量为2,局部变量c的数量为3(因此,putobject,2将分配给变量a等).这与a = 5相比唯一的副作用; c = 6是dup指令,这意味着您的方法的堆栈大小将大于1个插槽.但是这并不是特别重要,因为它只有解释器在这个特定的方法中才有效果,而且堆栈的内存是预先保留的,所以这只意味着堆栈指针将比其它方式递减1.所以基本上没有变化.即使是优化也可能会消失.