Ruby:数组是通过引用传递给函数的吗?

时间:2017-01-18 13:00:14

标签: arrays ruby pass-by-reference

我在下面有一个简单的代码

    def testarray
      arr_tree = [1,2,3,4,5]
      (1..3).each do |index|
        abcde(arr_tree)
        puts arr_tree[0]
      end
    end

    def abcde(node_tree)
      node_tree[0] += 100
    end

因此在testarray函数中,我有一个数组arr_tree,它被传递给函数abcde。我更改abcde函数内的数组值和testarray内的打印数组我在这里得到更改的值。所以输出是

101
201
301

但我期待

1
1
1

请解释为什么结果是这样的?我怎样才能达到预期的效果呢?

2 个答案:

答案 0 :(得分:4)

所有东西都是“在Ruby中作为对象传递的”。

数组是对象。

如果你想避免副作用,请复制参数

def abcde(node_tree)
  copy = node_tree.dup
  copy[0] += 100
  copy
end

虽然您将变量命名为tree,但请注意谨慎,dup方法仅生成浅层副本。 Shallow表示复制数组但不复制其元素。

为什么我上面没有说“通过引用传递”?

“按引用传递”是来自另一种语言的概念,在Ruby的上下文中没有意义。从技术上讲,Ruby的本机实现使用pass by value,其中value是指向对象结构的指针。然而,将Ruby视为使用“按值传递”会产生误导,因为它在传递给函数之前不会创建数据结构的副本。这似乎是你认为会发生的......

答案 1 :(得分:0)

您的假设是错误的: ,它始终是。您可以通过运行这个简单的测试轻松验证这一点:

def foo(bar)
  bar = 'reference'
end

baz = 'value'

foo(baz)

puts "Ruby is pass-by-#{baz}"
# Ruby is pass-by-value

更准确地说,Ruby是(也称为按对象调用按分享调用),这是一个特例按值传递,其中传递的始终是指向(可能)共享(可能)可变对象的指针:

def is_ruby_pass_by_value?(foo)
  foo.replace('More precisely, it is call-by-object-sharing!')
  foo = 'No, Ruby is pass-by-reference.'
end

bar = 'Yes, of course, Ruby *is* pass-by-value!'

is_ruby_pass_by_value?(bar)

p bar
# 'More precisely, it is call-by-object-sharing!'

然而,这实际上与您的问题无关。它与传递引用传递值无关。

  

因此在testarray函数中,我有一个数组arr_tree,它被传递给函数abcde。我更改abcde函数内的数组值和testarray内的打印数组我在这里得到了更改的值。

您获得更改的值,因为您更改了值。就这么简单。 Ruby不是纯函数式编程语言, 具有可变状态。如果你改变那个状态,那么旧状态就会消失,只有新状态存在。

你自己写道:

  

我改变了数组的值

好吧,如果更改数组,阵列会发生变化!整个代码中只有一个数组。

  

请解释为什么结果是这样的?

由于您更改了数组,因此数组会更改。

  

我怎样才能达到预期的效果?

您可以通过不更改数组来实现结果:

def testarray
  arr_tree = [1, 2, 3, 4, 5]
  (1..3).each do |index|
    abcde(arr_tree)
    puts arr_tree[0]
  end
end

def abcde(node_tree)
  [node_tree.first + 100, *node_tree.drop(1)]
end