2009-09-29 58 views
2

匿名陣列模塊級變量我在學習Ruby之中,以爲我很聰明用下面的代碼:修改在Ruby中

[@start,@end].map!{ |time| time += operation == :add ? amount : -(amount) } 

其中@啓動,@end兩個模塊級變量,操作可以是以下之一:add或:sub,並且amount是一個float值,用於調整@start和@end by。

授予它只會節省我一行代碼,但爲什麼這種方法不工作,我怎麼能得到類似的東西呢?

(我的預期輸出爲@開始/結束@相應地修改,但是單元的測試表明,它們留在它們的原始值。)

回答

5

在Ruby中重要的是要記住變量和它們所保持的對象之間的區別。簡單地設置變量將永遠不會改變該變量引用的對象。當你做a += b時,它只是a = a + b的簡寫。所以你要爲變量a賦一個新的值,而不是改變曾經存在的對象或者改變對該對象的任何其他引用。因此更改變量time不會更改@start

爲了分配給一個實例變量,您需要實際分配給該實例變量。這裏有一個方式做你正在尋找:

operation = :+ 
amount = 12 
@start, @end = [@start, @end].map {|time| time.send(operation, amount)} 

你會發現,我們不與:add:sub業務faffing周圍要麼 - 我們就可以通過郵件的實際名稱,我們要發送(在這種情況下,我使用+,但它可以是任何東西)。

如果你有一個大的,動態生成的ivars列表,你想設置,這只是一點點複雜。唯一的區別是需要按名稱獲取和設置ivars。

ivars = [:@start, :@end, :@something_else] 
operation = :+ 
amount = 12 
ivars.each {|ivar| instance_variable_set(ivar, instance_variable_get(ivar).send(operation, amount))} 
+0

非常感謝。假設不適用於Ruby。 – cfeduke 2009-09-29 14:09:50

2

在塊中的加法操作不修改「時間」 ,它會返回一個新值。所以數組中的元素不會被修改,它們會被替換。

+0

這是有道理的。我想沒有辦法讓我的代碼工作,因爲我想寫它。 – cfeduke 2009-09-29 06:29:06

3

+=運營商改變了time的價值,但它返回的time舊值,因此正確的代碼是:

@start,@end = [@start,@end].map!{ |time| time + (operation == :add ? amount : -amount) } 

編輯 更新代碼真正改變@start@end

+0

嗯,仍然沒有骰子。 @start + =操作==:添加?金額: - (金額)正在工作,但不是當我嘗試通過Array#map block來完成時。 :( – cfeduke 2009-09-29 06:55:12

+0

是的,這是有效的,謝謝!(我正在挑選Chuck的答案,因爲他很好地解釋了引擎蓋下發生了什麼,以及我如何能夠對Ruby思考) – cfeduke 2009-09-29 14:09:05