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

pet*_*ter 2 ruby parameters reference pass-by-reference pass-by-value

我回答了这个问题并偶然发现了一些奇怪的事情.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]
Run Code Online (Sandbox Code Playgroud)

use*_*740 5

非混淆项是由对象共享呼叫:原来的对象(而不是复制/克隆/重复)获得通过.

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

在Ruby中重新分配[本地]参数有没有影响呼叫者因为它不是通过参考使用呼叫.

在这个例子中,它显然不具备通过引用语义呼叫; 或者第二和第三种情况,它们分配回局部变量但不修改原始对象,就像第一种情况一样.

在"较低级别",实现是[引用参数]的值调用 - 也就是说,内部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
Run Code Online (Sandbox Code Playgroud)