如何让我的数组只在Ruby中本地操作(在函数内)?

时间:2016-08-22 15:44:52

标签: arrays ruby scope

当我运行下面的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]

2 个答案:

答案 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 按值传递

通过sitepoint

  

Ruby有可能在不同范围内定义的变量   知道了我发现大多数教程都简要地描述了它们   变量类型),但他们没有提到他们的范围   是

以下是详细信息:

类变量(@@a_variable):可从类定义和任何子类中获得。不在外面的任何地方提供。

实例变量(@a_variable):仅在特定对象中,在类实例中的所有方法中可用。不能直接从类定义中获得。

全局变量($a_variable):在Ruby脚本中随处可用。

局部变量(a_variable):取决于范围。你将会处理这些问题,从而遇到大多数问题,因为它们的范围取决于各种各样的事情。