2015-04-03 47 views
2

我刚刚开始学习Ruby,而且我在全局和局部变量范围方面遇到困难。全局数组正在被函数改变

在练习题上,我发现全局定义的数组正在被一个函数调用。如果我明确地将数组赋值给别的东西,则没有任何变化。但是如果我一遍又一遍地删除项目,这会从全局数组本身中删除它们。

为什么deletepop(我也测试过)方法有这种行为?我从阅读中了解到,这应该是而不是正在发生,函数内部的“数组”是对arr的值的引用,而不是变量arr

(我使用Ruby版本2+)

def change_int x 
    x += 2 
end 

def change_arr array 
    array = [4, 5, 6] 
end 

def pop_arr array 
    puts array 
    new_array = [] 

    while array.length > 0 
     new_array.push array[0] 
     array.delete_at 0 
    end 

    array 
end 

x = 5 
change_int x 
puts x == 5 # true 

arr = [1, 2, 3] 
change_arr arr 
puts arr == [1, 2, 3] # true 

old_arr = arr 
puts pop_arr arr 
puts arr == [1, 2, 3] # false 
puts "arr = #{arr}" # arr = [] 

回答

0

另请参阅:Ruby - Parameters by reference or by value?Is Ruby pass by reference or by value?

好奇的是,change_arr不会影响全局数组,但pop_arr会在您的代码中执行此操作。

发生了什么:ruby将对象的引用作为参数传递。就像Bartosz说的那样,你可以看到在这些方法的顶部,对象ID与你传入的对象相匹配;他们正在引用同一个对象。

因此,在pop_arr中,当您调用delete_at时,您正在对传入的同一对象进行操作,并且在该方法返回后更改仍然存在。

在change_arr中,区别在于您将内部变量赋值给新对象。当你传入参数数组时,内部变量引用了你传入的同一个对象。当你实例化一个新的Array对象并为它分配内部数组变量时,内部变量现在引用了一个不同的对象。

def change_arr array 
    puts "change id: #{array.object_id}" 
    array = [4, 5, 6] 
    puts "change id2: #{array.object_id}" 
    array 
end 

这就是为什么在方法结束后更改不会持续。如果您想变化持续下去,你不得不说

array = change_arr(array) 

希望有所帮助。

+0

很清楚,谢谢!帮助我更好地处理上面的重要评论。 – kevlarr 2015-04-04 13:52:01

2

你可以通过调用pop_arr之前和内部pop_arr这些数组是相同的对象打印#object_id看到。这意味着参数在Ruby中通过引用传递给函数。

这里是代码:

def pop_arr(array) 
    puts array.object_id 
    # Rest of the fucntion 
end 

arr = [1, 2, 3] 
puts arr.object_id 
pop_arr(arr) 

所有这一切都意味着,当你编辑函数内部数组它将有被传递物体上的效果。 #delete,#delete_at, #pop是改变它们所在的阵列的操作。

+0

当你说'x + = 2'时,你说的是参考x,加2并重新分配它。这意味着方法外部的引用'x'指向的东西不会改变。相比之下,对于数组,您不改变参考,您正在更改数值。 – BaroqueBobcat 2015-04-04 00:16:04

+0

不,参数不是通过引用在Ruby中传递,它们总是*通过值传递,就像在Smalltalk,Java,C,JavaScript,Python,C#(默认),C++(默认)等一样。 C#或C++,根本没有办法在Ruby中通过引用传递。这里是一个简单的测试,看看Ruby是传递值还是传递引用。不要听我的话,只要问Ruby自己! 'def foo(bar)bar ='reference'end; baz ='价值'; FOO(巴兹);放入“Ruby是传递 - #{baz}”#Ruby是传递值'。 – 2015-04-04 12:16:31

+0

另请参见[是通过引用还是按值传递Ruby?](http://stackoverflow.com/a/10330589/2988)。如果您知道如何阅读C#,我写了一个小例子,演示了传递值和传递引用之间的区别。 C#是一种很好的语言,因为它具有值类型和引用类型,并且支持按值传递和传递引用,所以您可以演示所有四种组合(按值传递值类型,通过引用类型传递值,传递值类型引用,并通过参考引用类型)在一个单一的程序:http://stackoverflow.com/a/12438174/2988 – 2015-04-04 12:23:32