为啥这个 Ruby 方法通过引用传递它的参数

Posted

技术标签:

【中文标题】为啥这个 Ruby 方法通过引用传递它的参数【英文标题】:Why this Ruby method passes it's argument by reference为什么这个 Ruby 方法通过引用传递它的参数 【发布时间】:2015-10-08 23:47:27 【问题描述】:

我回答了this 问题并偶然发现了一些奇怪的东西。 Ruby 按值传递其参数,但变量本身是引用。 那么为什么第一个方法似乎是通过引用传递它的参数呢?

require 'set'
require 'benchmark'

def add_item1!(item, list)
  list << item unless list.include?(item)
end

def add_item2(item, list)
  list |= [item]
end

def add_item3(item, list)
  set = Set.new(list)
  set << item
  list = set.to_a
end

array1 = [3,2,1,4]
add_item1!(5, array1)
p array1 # [3, 2, 1, 4, 5]

array2 = [3,2,1,4]
add_item2(5, array2) 
p array2 # [3, 2, 1, 4]

array3 = [3,2,1,4]
add_item3(5, array3)
p array3 # [3, 2, 1, 4]

【问题讨论】:

【参考方案1】:

不混淆的术语是Call by Object-Sharing:原始对象(并且不是副本/克隆/副本)被传递。

共享调用的语义与引用调用的不同之处在于函数内函数参数的赋值对调用者不可见

在 Ruby 中,重新分配 [local] 参数对调用者没有影响,因为它使用引用调用。 p>

在这个示例代码中,它显然没有具有引用调用语义;或者第 2 和第 3 种情况,它们分配回 local 变量,但在其他情况下不修改原始对象,会像第一种情况一样工作。

在“较低级别”上,实现是按值调用 [of a Reference] - 也就是说,Ruby 在内部使用指针和诸如此类的东西 - 这就是为什么有时使用重载短语“按引用调用”的原因,经常忘记“按价值”部分..并导致这种混乱。


def add_item1!(item, list)
  # MUTATES the list object, which is the original object passed
  # (there is no copy/clone/duplication that occurred)
  list << item unless list.include?(item)
end

def add_item2(item, list)
  # this creates a NEW list and re-assigns it to the parameter
  # re-assigning to a local parameter does not affect the caller
  # the original list object is not modified
  list |= [item]
end

def add_item3(item, list)
  set = Set.new(list)
  set << item
  # this creates a NEW list from set and re-assigns it to the parameter
  # re-assigning to a local parameter does not affect the caller
  # the original list object is not modified
  list = set.to_a
end

【讨论】:

我明白了,我应该用.replace来修改原来的对象

以上是关于为啥这个 Ruby 方法通过引用传递它的参数的主要内容,如果未能解决你的问题,请参考以下文章

值传递和引用传递(不是引用类型的传递)的区别

Java 值传递 和引用传递

unity 传递数组是值传递还是引用

为啥复制构造函数应该在 C++ 中通过引用来接受它的参数?

Java 中的值传递和参数传递

为啥在通过 const 引用传递临时值时调用复制构造函数?