我刚刚开始研究Ruby,我在全局和局部变量范围方面遇到了困难。
处理一个练习题,我发现全局定义的数组正被一个调用它的函数改变。如果我明确地将数组分配给其他东西,则没有任何变化。但是,如果我逐个执行并删除项目,则会将它们从全局数组中删除。
为什么delete
和pop
(我也测试过)方法有这种行为?我从阅读中了解到这应该不正在发生,函数内部的“数组”是对arr
的值的引用,而不是变量arr
。 / p>
(我正在使用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 :(得分:2)
您可以在调用#object_id
之前打印pop_arr
,在pop_arr
内打印这些数组是相同的对象。这意味着参数在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
是更改制作它们的数组的操作。
答案 1 :(得分: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中,区别在于您将内部var分配给新对象。传入参数数组时,内部变量引用传入的同一对象。当您实例化一个新的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)
希望有所帮助。