2009-09-23 47 views
5

(對我之前的問題的跟進,Ruby: how can I copy a variable without pointing to the same object?Ruby:我該如何複製這個數組?

我正在寫一個簡單的Ruby程序來在.svg文件中做一些替換。第一步是從文件中提取信息並將其放入數組中。爲了防止每次調用該函數時從磁盤讀取文件,我試圖使用memoize設計模式 - 在第一次調用之後的每次調用中使用緩存結果。

要做到這一點,我使用了一個全局變量,只是該功能之前定義。但即使我在返回本地變量之前將該變量賦予本地變量,調用此變量的函數仍在修改全局變量。

這裏是我的實際代碼:

#memoize to keep from having to read original file on each pass 
$svg_filedata_cache = [] #the global variable 
def svg_filedata(filename) 
    if $svg_filedata_cache.empty? 
     File.open(filename, "r"){|f| $svg_filedata_cache = f.readlines} 
    end 
    svg_filedata_cache = $svg_filedata_cache.dup #try to copy it 
    return svg_filedata_cache #SHOULD point to a different object (but doesn't) 
end 

兩個問題(答案之一或兩者):

  1. 爲什麼其他的功能,採取和修改此處的值返回,也影響全局變量,儘管我用.dup來複制它?
  2. 我是Ruby的新手,我確信這不是最簡單的方法(我不喜歡全局變量)。你能提出一個更好的策略嗎?
+0

P.S.我意識到它應該真的是$ svg_filedata_cache [文件名],以允許使用不同文件名的函數調用,但在這種情況下不需要。 – 2009-09-23 12:39:17

+0

順便說一下,全局和返回的對象有不同的object_id,我相信你提到返回數組中的字符串,對吧? – khelll 2009-09-23 12:54:51

+0

@khell - 是的,我基於我原來的數組內容正在改變的事實。 – 2009-09-23 13:55:57

回答

9

修改欺騙陣列將不會影響原來的。但是,對數組內的字符串所做的修改將全局可見,因爲全局數組和duped數組仍然包含對相同字符串的引用(dup不執行深度複製)。

因此,要麼執行深拷貝(svg_filedata_cache = $svg_filedata_cache.map {|line| line.dup})或乾脆避免在琴絃變異操作。

+1

我沒有意識到數組中的每個字符串都是它自己的對象!我猜這是真的,「Ruby中的所有東西都是一個對象。」 :) – 2009-09-23 14:12:08

6

加強代碼位:

$svg_filedata_cache = [] #the global variable 
def svg_filedata(filename) 
    # Use ||= for memoiziation 
    $svg_filedata_cache ||= File.open(filename, "r"){|f| $svg_filedata_cache = f.readlines} 
    $svg_filedata_cache.dup #shallow copying 
end 

更新:一個簡單的技巧做深度複製的一般是:

def deep_copy(obj) 
    Marshal.load(Marshal.dump(obj)) 
end 
+0

So || =意思是「如果左邊是虛假的(空的),使用右邊?」 – 2009-09-23 13:01:50

+2

這意味着只有在變量尚未設置的情況下,纔會將右側值分配給左側變量。 – khelll 2009-09-23 13:40:10

2

全球很可能不被修改,但元素它和你的.dup參考文件正在改變。爲了使它更加規範ruby,擺脫全局,使用一個類,並在initialize函數中讀取該文件。 (構造函數)使數組成爲@v的實例變量。