我写了两个 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"现在是一个空哈希。请说明为什么会发生这种情况?
这是简单的答案:
在 ruby 中,您可以通过引用将变量与对象一起传递。将 Object 分配给变量时,该变量实际上并不包含 Object 本身。相反,它仅包含对该对象的引用。
为了了解将变量作为参数发送的工作原理,开始查看引用和对象之间的差异可能会有所帮助:对象本身并不驻留在变量中,变量指向内存中对象的引用,因此,如果一个变量指向另一个对象并对其进行修改, 这并不意味着它修改了它之前引用的对象。
对于您来说,重要的是要了解 foo 方法中的 bar 参数实际上只是对内存中对象的引用,而不是对象本身。因此,如果 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 方法最初接收名为"bar"的参数,"hash_test"指向的哈希对象的引用,但会迅速将"bar"中的引用替换为对"pre_defined"变量指向的全新哈希对象的全新引用。现在,"bar"不会像"hash_test"指向同一个对象,因此"hash_test"指向的对象永远不会被修改。因此,"hash_test"包含的哈希对象从未真正填充过任何内容,并且在my_print尝试打印它时为空。
也就是说,因为 Ruby 是按值传递的,因此传递对象的引用。这与Java的行为类似。这意味着您在 foo-method 中只有引用的副本,重新分配它不会更改此方法之外的引用。
更详细地说:在您的第一个示例中,您将哈希传递给您的 foo 方法。引用将被复制,因此在 foo-方法中,您有一个引用的副本,该引用指向与 'hash_test' 相同的对象,但不是同一个对象。因此,调用 Hash 方法会更改方法外部对象的值。但是在第二个示例中,您没有更改给定 Hash 的值,而是将一个新的 Hash 对象分配给方法引用的副本,这对"hash_test"引用没有影响。