当我运行下面的 ruby代码时,为什么我的数组被全局操作?我怎样才能在函数范围内操作数组? a = [[1,0],[1,1]]def hasRowsWithOnlyOnes(array) array.map { |row| return true if row.keep_if{|i| i != 1 } == [] } fa
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]这不是范围问题,而是一个传递问题的论据
> Ruby中的所有变量都是对象的引用.
>将对象传递给方法时,会生成该对象引用的副本并将其传递给该对象.
这意味着方法中的变量数组和顶级变量a引用完全相同的数组.对数组所做的任何更改也将作为a的更改显示,因为两个变量都引用同一个对象.
您的方法通过调用Array#keep_if来修改数组.hold_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
这应该避免,因为它很慢.