2012-04-22 83 views
2

我有Ruby代碼:混亂的Ruby的方法返回值

def test_111(hash) 
    n = nil 
    3.times do |c| 
     if n 
     n[c] = c 
     else 
     n = hash 
     end 
    end 
end 

a = {} 
test_111(a) 
p a 

爲什麼它打印{1=>1, 2=>2}不是{}

在test_111方法中,散列a使用相同的內存?

如何在test_111方法中更改a值?

我不明白

回答

4

哈希通過引用傳遞。所以,當你改變一個方法參數(這是一個哈希)時,你改變了原始哈希。

爲了避免這種情況,應該克隆哈希。

test_111(a.dup) 

這將創建一個淺拷貝(也就是說,它不會克隆你可能擁有的子哈希)。

什麼淺拷貝是一個小例證:

def mutate hash 
    hash[:new] = 1 
    hash[:existing][:value] = 2 
    hash 
end 

h = {existing: {value: 1}} 

mutate h # => {:existing=>{:value=>2}, :new=>1} 
# new member added, existing member changed 
h # => {:existing=>{:value=>2}, :new=>1} 



h = {existing: {value: 1}} 

mutate h.dup # => {:existing=>{:value=>2}, :new=>1} 
# existing member changed, no new members 
h # => {:existing=>{:value=>2}} 
+0

JörgW Mittag認爲Ruby是通過價值傳遞的。 http://stackoverflow.com/a/6528257/38765 – 2012-04-22 23:25:56

+0

他也承認通過的值可以是指針。從糟糕的編碼者的角度來看,這是參考:) – 2012-04-23 00:12:04

0

在Ruby中,幾乎每一個對象是按引用傳遞。這意味着,當你做的

a = b 

簡單的東西,除非是簡單的類型之一,這種分配ab將指向同樣的事情。

這意味着,如果你改變第二個變量,第一個受到影響的相同方式:

irb(main):001:0> x = "a string" 
=> "a string" 
irb(main):002:0> y = x 
=> "a string" 
irb(main):003:0> x[1,0] = "nother" 
=> "nother" 
irb(main):004:0> x 
=> "another string" 
irb(main):005:0> y 
=> "another string" 
irb(main):006:0> 

,當然同樣適用於哈希:

irb(main):006:0> a = { :a => 1 } 
=> {:a=>1} 
irb(main):007:0> b = a 
=> {:a=>1} 
irb(main):008:0> a[:b] = 2 
=> 2 
irb(main):009:0> a 
=> {:a=>1, :b=>2} 
irb(main):010:0> b 
=> {:a=>1, :b=>2} 
irb(main):011:0> 

如果你不想這種情況發生,使用.dup.clone

irb(main):001:0> a = "a string" 
=> "a string" 
irb(main):002:0> b = a.dup 
=> "a string" 
irb(main):003:0> a[1,0] = "nother" 
=> "nother" 
irb(main):004:0> a 
=> "another string" 
irb(main):005:0> b 
=> "a string" 
irb(main):006:0> 

莫st人dupclone具有相同的效果。

所以,如果你寫被修改的修改其參數之一,除非你特別想通過調用該函數的代碼可以看出這些變化,你應該先DUP參數的函數:

def test_111(hash) 
    hash = hash.dup 
    # etc 
end 

您的代碼的行爲稱爲副作用 - 程序狀態的更改不是該函數的核心部分。副作用通常要避免。