1

我写了两个 ruby​​ 文件进行测试

测试.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)

它按我的预期工作,输出是

键 => 值

但是当我将 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”现在是一个空散列。请说明为什么确实会发生这种情况?

4

2 回答 2

3

这是简单的答案:

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

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

你要明白的重要一点是 foo 方法中的 bar 参数实际上只是对内存中 Object 的 REFERENCE,而不是 Object 本身。因此,如果 bar 曾经指向该对象,但它现在正在引用另一个对象,它将修改它所引用的内容,而不是它指向的先前对象。这是最后一个 test.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 方法虽然最初接收“hash_test”指向的哈希对象的引用作为名为“bar”的参数,但很快将“bar”中的引用替换为对全新哈希对象的全新引用,“ pre_defined" 变量指向。现在“bar”与“hash_test”指向的对象不同,因此“hash_test”指向的对象永远不会被修改。因此,“hash_test”包含的哈希对象从未真正填充任何内容,并且当 my_print 尝试打印它时为空。

于 2012-05-24T07:30:27.813 回答
1

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

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

于 2012-05-24T06:45:08.250 回答