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



我写了两个 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"引用没有影响。

最新更新