【问题标题】:When passing objects as parameters, are they passed by reference?将对象作为参数传递时,它们是通过引用传递的吗?
【发布时间】:2011-06-29 20:44:46
【问题描述】:

如果我执行以下任一操作,是否会对性能产生影响:

def do_something(user, article)
...
end

def do_something(user_id, article_id)
  ..
end

我更喜欢传递对象,因为我可能需要其他属性。

【问题讨论】:

  • 即使有性能影响,也不要过早优化。如果您认为需要其他对象属性,请传入对象。
  • 当你说user_id时,你是指为Ruby对象提供的object_id(甚至nil有一个object_id),还是ActiveRecord提供的唯一数据库id?

标签: ruby-on-rails ruby pass-by-reference


【解决方案1】:

是的

两个方法调用所花费的时间大致相同。

(很高兴了解性能影响并且您提出了一个合理的问题,但即便如此,关于早期优化的标准免责声明1在技术上仍然适用。)


1. 首先,使程序工作。 然后,简介。 最后,也许,优化。
Donald Knuth said: 我们应该忘记小的 效率,说大约 97% 时间:过早优化是 万恶之源。

【讨论】:

  • +1 标准免责声明(除了 Knuth 的引用)是您自己提出的,还是您在某处听到的?
  • 我今天做了这个,但这里有点像“答案模式”,对吧?
  • 也许我们应该将其称为标准优化免责声明,并有一个这些词可以链接到的元帖子。
【解决方案2】:

回复:https://stackoverflow.com/a/6528257(在撰写本文时我没有足够的声誉来发表评论)

啊,但是 Jörg,如果你真的操纵参数,而不是给它分配一个新对象,方法的行为会有所不同。使用 .replace 而不是 = 会给你这个:

def is_Ruby_pass_by_value_or_reference?(parameter)
  parameter.replace 'Ruby is pass-by-reference.'
end

var = 'Ruby is pass-by-value.'

is_Ruby_pass_by_value_or_reference?(var)

puts var
# Ruby is pass-by-reference.

其实我们再详细说明一下,只是为了说明区别:

def is_Ruby_pass_by_value_or_reference?(parameter)
  parameter.replace 'Ruby is pass-by-reference.'
  parameter = "This assigns a whole new object to 'parameter', but not to 'var'."
  puts parameter
end

var = 'Ruby is pass-by-value.'

is_Ruby_pass_by_value_or_reference?(var)
# This assigns a whole new object to 'parameter', but not to 'var'.

puts var
# Ruby is pass-by-reference.

【讨论】:

  • 这应该是答案。太棒了..我想知道参考是否也传递了固定数字?它们并不总是“对象”,所以也许它们是特殊的。
  • -1。这是错误的。引用传递意味着被调用者可以操纵正在传入的调用者的变量绑定。在 Ruby 中不是这种情况。事实上,您的代码甚至 显示 Ruby 中并非如此,因此您的代码显示 Ruby 不是 传递引用。如果它通过引用传递,那么你的最后一行将打印This assigns a whole new object to 'parameter', but not to 'var'.而不是Ruby is pass-by-reference. 你的代码显示的是Ruby允许你改变共享可变状态。但这无论如何都没有争议,没有人声称 Ruby 是一个……
  • ……纯函数式语言。引用传递意味着变量绑定 itself 被传递给被调用者,因此对该变量绑定的更改(换句话说:对变量的赋值)对调用者是可见的。您的代码清楚地表明情况并非如此,因此它表明 Ruby 不是通过引用传递的。
  • 嗯,这都是非常有说服力的行话,Jörg,但事实是,当人们问“这是通过引用传递”时,他们真正的意思是,“一个方法可以改变一个变量传递给它?”正如我所证明的,答案是“是”。如果您不希望您的方法执行此操作,则应将 parameter.dupparameter.clone(分别为浅拷贝和深拷贝)分配给某些东西并使用它。
  • 非常好的答案,在日常的红宝石编程中非常方便。谢谢!!!
【解决方案3】:

不,Ruby 从不通过引用传递。 Ruby 是按值传递的。总是。没有例外。

def is_Ruby_pass_by_value_or_reference?(parameter)
  parameter = 'Ruby is pass-by-reference.'
end

var = 'Ruby is pass-by-value. Always. No exceptions.'

is_Ruby_pass_by_value_or_reference?(var)

puts var
# Ruby is pass-by-value. Always. No exceptions.

如果 Ruby 通过引用传递,这将打印 Ruby is pass-by-reference.

【讨论】:

  • 您能详细说明一下吗?它已被多次讨论并声明 ruby​​ 是通过引用传递ruby-forum.com/topic/41160。该链接中的第二个条目总结了这一切。
  • @so_mv:传递的值是指针这一事实并没有改变 Ruby 是按值传递的事实。
  • Jorg.. 传递的值是指针,在某种程度上定义了通过引用传递的术语。 Patrik 对您的代码的扩展也显示了您的错误。
  • @daveatflow:不,它确实不是“在某种程度上定义了通过引用传递这个术语”。该术语不是“某种定义的”。它是精确定义的,并且已经定义了几十年。 什么被传递是完全和完全无关的。它可以是整数,可以是对象,可以是指针,甚至可以是复活节兔子。 相关的是如何它被传递:是被传递的变量的内容的副本(pb-value)还是变量绑定本身被传递(pb-reference)。在后一种情况下,操作变量绑定对调用者是可见的。
  • @daveatflow:@Patrick 的代码实际上准确地表明 Ruby 不是传递引用。如果它,那么最后一行将打印This assigns a whole new object to 'parameter', but not to 'var'.,而不是打印Ruby is pass-by-reference.
【解决方案4】:

例如,我会使用 _id 变体。我更喜欢始终能够获得对象的正确状态。处理陈旧的东西从来都不是一件有趣的事。

【讨论】:

    【解决方案5】:

    好吧,ruby 中的所有内容都是 Object(所有内容都继承自 Object),并且 ruby​​ 总是通过引用传递对象,因此您的两个示例都是通过引用传递的!

    【讨论】:

    • 这并不完全正确。许多不可变的常量,例如小整数,实际上在 Ruby 中是按值传递的。这并没有什么区别,因为它们仍然是对象,并且它并没有真正改变方法调用的速度,但是从技术上讲,对于称为 立即数的事物有一个幕后的按值调用。 见:redmine.ruby-lang.org/issues/show/1844
    • 你错了! Ruby 没有任何传递值的概念。变量总是对对象的引用。如果一切都是按值传递的对象是没有意义的。
    • Ruby 确实通过引用传递除了直接值类之外的所有内容
    • 不幸的是,这些术语不适用于现代语言。对象是按引用传递的,但引用是按值传递的。两者兼而有之。在任何语言中“按值”传递对象都非常罕见(尽管这可以用 C 中的结构来完成,但通常不是,并且总是用 Ruby 中的某些小对象来完成),我想人们可以合理地讨论一下引用是如何传递的。
    • @eggie5:Ruby 是按值传递的。传递的值是指针(或者在某些情况下是立即数,但它们也是不可变的,因此实际上不可能观察到差异),但值是什么无关紧要,不会改变语义。
    猜你喜欢
    • 2018-08-17
    • 2011-12-11
    • 2018-08-28
    • 1970-01-01
    • 2016-04-18
    • 2012-10-31
    • 2011-09-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多