2011-01-29 92 views
3

我想比較一個case語句的多個變量,並且當前正在考慮覆蓋數組的等號運算符(===)是執行此操作的最佳方式。這是最好的方法嗎?使用數組的多個變量的Ruby case語句

下面是一個例子用例:

def deposit_apr deposit,apr 
    # deposit: can be nil or 2 length Array of [nil or Float, String] 
    # apr: can be nil or Float  
    case [deposit,apr] 
    when [[Float,String],Float] 
     puts "#{deposit[0]} #{deposit[1]}, #{apr*100.0}% APR" 
    when [[nil,String],Float] 
     puts "#{apr*100.0}% APR on deposits greater than 100 #{deposit[1]}" 
    when [[Float,String],nil] 
     puts "#{deposit[0]} #{deposit[1]}" 
    else 
     puts 'N/A' 
    end 
end 

唯一的問題是陣列情況下等於操作者不適等於所述數組的元素的情況。

ruby-1.9.2-p0 > deposit_apr([656.00,'rupees'],0.065) 
N/A 

它將如果我重寫,但我不知道如果我這樣做我會打破:

class Array 
    def ===(other) 
    result = true 
    self.zip(other) {|bp,ap| result &&= bp === ap} 
    result 
    end 
end 

現在,所有的工作:

ruby-1.9.2-p0 > deposit_apr([656.00,'rupees'],0.065) 
656.0 rupees, 6.5% APR 

我錯過什麼?

回答

2

如果您擔心通過更改Array行爲來破壞某些東西,當然這是一個合理的擔心,那麼只需將修改後的運算符置於Array的子​​類中即可。

-1

這絕對不是最好的方法。甚至更多 - 你不應該重新定義標準類的方法,因爲核心功能可能取決於它 - 然後有樂趣的調試。

防禦風格很不錯(有很多類型檢查和whatnot),但它通常會損害性能的可讀性。

如果你知道除了一堆浮標和字符串之外,你不會傳遞任何其他內容 - 爲什麼你需要所有這些檢查?

IMO使用異常捕獲和解決問題的根源,不要試圖在某處解決問題的中間

8

我發現這個問題,因爲我一直在尋找在多個變量運行case聲明,但是,通過以下,得出的結論是需要比較多個變量可能表明需要不同的方法。 (我回到我自己的代碼,得出這個結論,發現即使是一個Hash也幫助我編寫易於理解的代碼。)

寶石今天使用"no monkey patching" as a selling point。重寫操作員可能不是正確的方法。猴子修補對於實驗來說非常適合,但事情太容易出錯。

此外,還有很多類型檢查。在爲鴨子打字設計的語言中,這清楚地表明需要採用不同的方法。例如,如果我傳入整數值而不是浮點數,會發生什麼情況?我們會得到'N/A',儘管這不太可能是我們想要的。

你會注意到問題中給出的例子很難理解。我們應該能夠找到一種更清楚地向讀者表達這一邏輯的方法(以及作者,當他們在幾個月內再次重訪代碼並且必須解釋發生了什麼時)。

最後,由於有多個數字和關聯的邏輯,所以至少有一個value object類型的類(Deposit)需要寫入。

對於清潔度,我打算假設nil APR可以被認爲是0.0%年利率。

class Deposit 
    def initialize(amount, unit='USD', options={}) 
    @amount = amount.to_f # `nil` => 0.0 
    @unit = unit.to_s # Example assumes unit is always present 
    @apr = options.fetch(:apr, 0.0).to_f # `apr: nil` => 0.0 
    end 
end 

一旦我們有我們的存款對象,我們就可以實現打印邏輯,而無需在所有case語句。

class Deposit 

    # ... lines omitted 

    def to_s 
    string = "#{@amount} #{@unit}" 
    string << ", #{@apr * 100.0}% APR" if @apr > 0.0 
    string 
    end 
end 

d = Deposit.new(656.00, 'rupees', apr: 0.065) 
d.to_s 
# => "656.0 rupees, 6.5% APR" 

e = Deposit.new(100, 'USD', apr: nil) 
e.to_s 
# => "100.0 USD" 

f = Deposit.new(100, 'USD') 
f.to_s 
# => "100.0 USD" 

結論:如果你在一個case語句比較多個變量,用它作爲一種氣味暗示更深的設計問題。多變量case可能表明有一個對象想要創建。