2012-04-22 57 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 

您的代码的行为称为副作用 - 程序状态的更改不是该函数的核心部分。副作用通常要避免。