2012-11-07 17 views
16

我偶爾會看到begin...end紅寶石中使用的塊沒有任何rescue,else,ensure等之間的語句。例如:如果沒有`rescue'作爲代碼塊,Ruby的`begin ... end`會產生意想不到的後果嗎?

foo = begin 
    whatever = 3 
    "great" 
    42 
end 

編碼器的意圖,似乎是使用begin...end塊只是它的塊分組質量(好像begindo)。就我個人而言,我認爲這種用法違反了最小驚喜原則(begin意味着對我的異常處理)。

以這種方式使用begin...end會有什麼意想不到的後果嗎? begin...end塊有任何語義差異(可能在異常處理?),使這種用法很危險?

Ruby的語法是令人難以置信的微妙,如果在這裏等待着奇怪的陷阱,我不會感到驚訝。

+0

我從來沒有見過這樣的代碼。你能指出一個公共的源文件嗎? –

+0

@SergioTulentsev:直到我能找到一個源文件,這裏有一個博客評論:http://blog.rubybestpractices.com/posts/rklemme/003-The_Universe_between_begin_and_end。html#comment-9011441 – pje

+0

我不知道它會如何危險,但是IMO錯了:它應該是一種方法。 –

回答

27

我有時候會用這個,如果我想給某個變量賦值,但是我必須先計算出我想賦值的值。它使代碼更加整潔。我認爲這是用戶偏好。基本上你在說:我正在分配一些東西給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相比,唯一的副作用是dup指令,這意味着您的方法的堆棧大小將增加1個時隙。但這並不是特別重要,因爲它只在解釋器位於這個特定方法內時才起作用,並且堆棧的內存是預先保留的,所以它只意味着堆棧指針會比其他方式減少1。所以基本上沒有改變。隨着優化打開,即使dup可能會消失。

+1

這並不回答我的問題。 – pje

+0

就像我說的那樣,它是完全有效的,所以沒有任何意想不到的後果。這只是一種代碼風格的東西。 – mrbrdo

+0

,這是一個很好的意見,但「沒有任何意想不到的後果」不在你的答案。 – pje

相關問題