我在下面有一个简单的代码
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
请解释为什么结果是这样的?我怎样才能达到预期的效果呢?
答案 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)
您的假设是错误的:ruby 不 pass-by-reference,它始终是pass-by-value。您可以通过运行这个简单的测试轻松验证这一点:
def foo(bar)
bar = 'reference'
end
baz = 'value'
foo(baz)
puts "Ruby is pass-by-#{baz}"
# Ruby is pass-by-value
更准确地说,Ruby是call-by-object-sharing(也称为按对象调用和按分享调用),这是一个特例按值传递,其中传递的值始终是指向(可能)共享(可能)可变对象的指针:
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