当我运行下面的ruby代码时,为什么我的数组被全局操作?我怎样才能让数组只在函数范围内被操作?
a = [[1,0],[1,1]]
def hasRowsWithOnlyOnes(array)
array.map { |row|
return true if row.keep_if{|i| i != 1 } == []
}
false;
end
puts a.to_s
puts hasRowsWithOnlyOnes(a)
puts a.to_s
$ ruby test.rb
输出:
[[1, 0], [1, 1]]
true
[[0], []]
我无法让它发挥作用。我甚至尝试过.select{true}
并将其分配给一个新名称。范围如何在Ruby for Arrays中运行?
仅供参考,$ ruby -v
:
ruby 2.2.1p85 (2015-02-26 revision 49769) [x86_64-linux]
答案 0 :(得分:7)
Ruby中的所有变量都是对象的引用。
将对象传递给方法时,会创建该对象引用的副本并将其传递给该对象。
这意味着方法中的变量array
和顶级变量a
指的是完全相同的数组。对array
所做的任何更改也会显示为a
的更改,因为这两个变量都引用同一个对象。
您的方法通过调用Array#keep_if来修改数组。 keep_if
方法就地修改了数组。
最好的解决方法是使其方法不会修改传入的数组。这可以使用Enumerable#any?和Enumerable#all?方法非常巧妙地完成:
def has_a_row_with_only_ones(array)
array.any? do |row|
row.all? { |e| e == 1 }
end
end
此代码表示如果对于任何行,该行中的每个元素都是1,则该方法返回true。这些方法不会修改数组。更重要的是,他们清楚地传达了方法的意图。
如果您希望将方法作为通过数组副本的方式传递给它,以便可以修改该数组,而不在该方法外部看到该修改,那么您可以制作该数组的深层副本。如this answer所示,您可以定义此方法以进行深层复制:
def deep_copy(o)
Marshal.load(Marshal.dump(o))
end
然后,在方法的顶部,进行深层复制:
def has_a_row_with_only_ones(array)
array = deep_copy(array)
# code that modifies array
end
这应该避免,因为它很慢。
答案 1 :(得分:0)
Ruby 按值传递
Ruby有可能在不同范围内定义的变量 知道了我发现大多数教程都简要地描述了它们 变量类型),但他们没有提到他们的范围 是
以下是详细信息:
类变量(@@a_variable
):可从类定义和任何子类中获得。不在外面的任何地方提供。
实例变量(@a_variable
):仅在特定对象中,在类实例中的所有方法中可用。不能直接从类定义中获得。
全局变量($a_variable
):在Ruby脚本中随处可用。
局部变量(a_variable
):取决于范围。你将会处理这些问题,从而遇到大多数问题,因为它们的范围取决于各种各样的事情。