Ruby 中的“通过引用传递参数”?

'pass parameter by reference' in Ruby?

提问人:Cristian Diaconescu 提问时间:10/2/2008 最后编辑:Ry-Cristian Diaconescu 更新时间:5/16/2019 访问量:25160

问:

在 Ruby 中,是否可以通过引用传递具有值类型语义的参数(例如 Fixnum)? 我正在寻找类似于 C# 的“ref”关键字的东西。

例:

def func(x) 
    x += 1
end

a = 5
func(a)  #this should be something like func(ref a)
puts a   #should read '6'

顺便说一句。我知道我可以使用:

a = func(a)
Ruby 参数传递 引用

评论


答:

20赞 Christoph Schiessl 10/2/2008 #1

Ruby 根本不支持“通过引用传递”。一切都是一个对象,对这些对象的引用总是按值传递。实际上,在您的示例中,您正在按值传递对 Object 的引用副本。Fixnum

你的代码的问题在于,它不会修改传递的对象,而是创建一个全新的独立对象。x += 1Fixnum

我认为,Java 程序员会称对象为不可变对象。Fixnum

评论

4赞 Damien Pollet 5/3/2009
当变量和参数只能包含对对象的引用时,我不明白 Ruby 不会通过 ref 传递的东西。说引用是按值传递的,这与说对象是按引用传递的是一样的。
2赞 newacct 4/24/2012
@Damien:不,不是。通过引用传递(例如在 C++、C#、PHP、Perl 中)允许您分配给变量,就像您在外部作用域中分配给它一样。您在这里尝试做的事情可以通过真正的引用传递来实现;但不能按引用值传递。
8赞 Damien Pollet 4/24/2012
你是对的,我正在再次阅读克里斯托夫的回答和我的评论,我不同意我 2009 年的自己。嗯。。。
32赞 jmah 10/2/2008 #2

可以通过显式传入当前绑定来实现此目的:

def func(x, bdg)
  eval "#{x} += 1", bdg
end

a = 5
func(:a, binding)
puts a # => 6

评论

0赞 Cristian Diaconescu 4/3/2020
Ruby 绑定文档
0赞 Tim Baverstock 9/9/2020
这是一个可怕的骗局:涉及各种错别字、安全和丑陋风险。最好使用某种包装器,并将“绑定”留给“撬”之类的东西。
12赞 muesan 10/2/2008 #3

在 Ruby 中,你不能通过引用传递参数。对于您的示例,您必须返回新值并将其分配给变量 a,或者创建一个包含该值的新类并传递此类的实例。例:

class Container
attr_accessor :value
 def initialize value
   @value = value
 end
end

def func(x)
  x.value += 1
end

a = Container.new(5)
func(a)
puts a.value
8赞 Ivan Gusev 3/2/2015 #4

您可以尝试以下技巧:

def func(x) 
    x[0] += 1
end

a = [5]
func(a)  #this should be something like func(ref a)
puts a[0]   #should read '6'

评论

0赞 itarato 10/16/2017
从技术上讲,这也取代了写入时的变量(和列表中的引用)。
0赞 Tim Baverstock 9/9/2020
@itarato a 和 x 在其生存期内都指向同一个列表,因此没有任何东西可以替换任何变量,但列表的第一个条目会更改为指向不同的数字。我喜欢这个技巧,因为使用列表感觉比包装类 .get/.set 方法的心理开销要少,但这确实意味着您需要记住使用 [0] 取消引用它。
2赞 Sam Liao 3/2/2016 #5

http://ruby-doc.org/core-2.1.5/Fixnum.html

Fixnum 对象具有即时值。这意味着当它们被分配或 作为参数传递,则传递实际对象,而不是引用 那个对象。

此外,Ruby 是按值传递的。

-1赞 Ivan Cenov 5/16/2019 #6

但是,复合对象(如哈希)似乎是通过引用传递的:

fp = {}
def changeit(par)
  par[:abc] = 'cde'
end

changeit(fp)

p fp

{:abc=>"cde"}

评论

0赞 Tim Baverstock 9/9/2020
哈希值按值传递,但值是对可变对象的引用。所以 fp 总是指向同一个哈希对象实例,但 changeit 会修改其内容。您可以通过打印fp.object_id和par.object_id来确认这一点。你不能仅仅通过给 par 分配一个不同的哈希来影响 fp 的值——这是“通过引用传递”所允许的。