2010-06-12 63 views
2

這是一個紅寶石bug嗎?Ruby奇怪的分配行爲

target_url_to_edit = target_url 

if target_url_to_edit.include?("http://") 
    target_url_to_edit["http://"] = "" 
end 

logger.debug "target url is now #{target_url}" 

這將返回target_url不包含http://

回答

10

你需要複製在內存中的對象,因爲變量名都只是在內存中的對象的引用:

target_url_to_edit = target_url.dup 

現在target_url_to_edit被分配日的新副本e原始對象。

對於您的情況下,該代碼可能不會在短短的一行相同的(沒有DUP,沒有如果):

target_url_to_edit = target_url.sub(%r{^http://}, "") 
0

這是不是一個錯誤。這是預期行爲,因爲target_url_to_edit指向內存中的相同對象,因爲Ruby使用引用來分配對象。如果你知道C,它與指針類似。

-1

這裏是如何改變自己的行爲,迫使路過值(注意星號):

target_url_to_edit = *target_url.to_s 

if target_url_to_edit.include?("http://") 
    target_url_to_edit["http://"] = "" 
end 

logger.debug "target url is now #{target_url}" 

而且就像紅寶石很多事情,很難找到其中它的記錄......

+2

我不認爲明星是你想要的。它會將普通對象轉換爲數組。只要'target_url.to_s'應該足以得到一個新的字符串。很難找到記錄在哪裏? Ruby變量是引用的事實? – Chuck 2010-06-12 18:46:42

+0

你能解釋一下這與傳遞值有關嗎?首先,Ruby總是*傳值。沒有必要「強迫價值傳遞」,實際上沒有辦法強制按值傳遞,因爲傳值是Ruby唯一支持的評估策略。其次,這與評估策略無關。這是共享可變狀態的一個簡單結果。我們已經教了60年,共享可變狀態是不好的,我們忽視了這個建議,並且使用共享可變狀態60年,因此我們必須忍受這樣的後果。 – 2010-06-12 21:34:37

+0

Ruby總是傳值,沒有任何其他的支持。但對於沒有經驗的程序員來說,它看起來像通過引用。實際上,通過使用「。」您正在取消引用對象指針。使用[]運算符就是一個與'var。[](「http://」)相同的方法調用...' – hurikhan77 2010-06-12 22:58:40

5

不,這不是在Ruby中的一個錯誤,這是多麼的共享可變狀態的作品,不僅在Ruby中,而且在任何編程語言。

想想這樣:我媽媽叫我「兒子」,我的朋友叫我「Jörg」。如果我剪了頭髮,那麼用哪個名字來引用我並不重要:我是同一個人,不管你是否稱我爲「兒子」或「Jörg」或「Mittag先生」或「嘿, douchebag「,所以我的頭髮總是很短。如果你用不同的名字給我打電話,它不會神奇地長大。

同樣的事情發生在你的代碼中:你用兩個不同的名稱來引用字符串,但是使用哪個名稱並不重要;如果字符串改變,那麼它會改變。

當然,解決方案不是共享可變狀態,也不會改變共享狀態,就像在@ hurikhan77的答案中一樣。

+0

我喜歡這個比喻! – 2010-06-13 07:14:18

+0

對於「但是使用任何編程語言」,您需要知道Ruby沒有任何原語類型,這些原語類型在分配過程中會被簡單地複製。一切都是一個對象,就像給大多數其他語言分配一個指向對象的指針一樣。 – hurikhan77 2012-07-31 18:26:48