关于ruby参数传递的一些令人困惑的事情

时间:2012-05-24 06:36:43

标签: ruby variables parameters parameter-passing scope

我已经为测试编写了两个ruby文件

test.rb:

#!/usr/bin/ruby

def foo(bar)
    bar['key'] = 'value'
end

def my_print(a)
    a.each{|k,v|
        puts "#{k} => #{v}"
    }
end

test_drive.rb:

#!/usr/bin/ruby

require 'test.rb'

hash_test = Hash.new

foo(hash_test)

my_print(hash_test)

它的效果与我的预期一致,输出为

  

key =>值

但是当我将test.rb归为

#!/usr/bin/ruby

def foo(bar)
    pre_defined = {'key' => 'value'}
    bar = pre_defined
end

def my_print(a)
    a.each{|k,v|
        puts "#{k} => #{v}"
    }
end

这里我使用了预定义的哈希值,但现在它没有输出任何内容。 “hash_test”现在是一个空哈希。 请说明为什么会发生这种情况?

2 个答案:

答案 0 :(得分:3)

这是一个简单的答案:

在ruby中,您通过引用传递带有对象的变量。将Object分配给变量时,该变量实际上并不包含Object本身。相反,它只包含对该对象的引用。

可能有助于您开始查看引用和对象之间的差异,以便了解如何将变量作为参数发送:Object本身不驻留在变量中,变量指向内存中Object的引用因此,如果一个变量指向另一个对象并对其进行修改,那并不意味着它修改了之前引用的Object。

重要的是你要理解的是foo方法中的bar参数实际上只是对内存中Object的引用,而不是Object本身。因此,如果bar一旦指向Object,但它现在引用另一个Object,它将修改它引用的内容,而不是它指向的前一个对象。这是最后一次测试的代码.rb略微评论,以便您更好地理解它:

def foo(bar) # here "bar" points to the same object as "hash_test"
    pre_defined = {'key' => 'value'}  # here a new object is created and referenced
    bar = pre_defined # now "bar" points to a new object and forgets about "hash_test"
end

def my_print(a) # here "a" holds a reference to "hash_test" which is empty
    a.each{|k,v|  # "a" is empty, so it has nothing to put
        puts "#{k} => #{v}" 
    }
end

我希望这会有所帮助。如果你需要更详细的东西:

您的上一版test.rb在test_drive.rb中打印空哈希的原因是因为引用“hash_test”指向的哈希对象根本没有被修改。相反,foo方法虽然最初作为参数“bar”接收“hash_test”所指向的哈希对象的引用,但很快用“bar”中的引用替换了对全新哈希对象的全新引用“ pre_defined“变量指向。现在“bar”不指向与“hash_test”相同的Object,因此“hash_test”指向的Object永远不会被修改。因此,“hash_test”包含的哈希对象从未真正填充任何内容,并且当my_print尝试打印时为空。

答案 1 :(得分:1)

也就是说,因为Ruby是通过值传递的,所以传递了对象的引用。这与Java的行为类似。这意味着您只有foo方法中的引用副本,并且重新分配它不会更改此方法之外的引用。

更详细: 在你的第一个例子中,你将哈希传递给你的foo方法。引用将被复制,因此在foo方法中,您有一个引用的副本,该副本指向与'hash_test'相同的对象,但不是同一个。因此,调用Hash方法会更改方法之外的对象的值。但是在你的第二个例子中你没有改变给定Hash的值,你将一个新的Hash对象分配给方法引用的副本,这对'hash_test'引用没有影响。