0

我不确定将对象传递给模块方法时会发生什么。对象是通过引用还是通过副本传递的?就像在这个例子中一样:

module SampleModule
  def self.testing(o)
    o.test
  end
end

class SampleClass
  def initialize(a)
    @a = a
  end

  def test
    @a = @a + 1
  end
end

sample_object = SampleClass.new(2)
3.times do
  SampleModule.testing(sample_object)
end
p sample_object # => #<SampleClass:somehexvalue @a=5>

似乎是通过参考。这个真的不清楚。

4

3 回答 3

2

Ruby 中的所有变量都是对对象的引用。您不能像在 C、C++ 或 Perl 中那样选择“按值传递”与“按引用传递”。Ruby 实际上强制按值传递,否则没有其他选择。但是,发送的值始终是对对象的引用。这有点像使用 C 或 C++,其中所有成员变量都是指针,或者使用 Perl,您必须始终使用引用,即使使用简单的标量也是如此。

我认为正是这种变量与对象数据的分离让您感到困惑。

几点:

  • 变量分配永远不会覆盖可能指向同一对象的其他变量。这几乎就是按值传递的定义。但是,这并不能满足您对对象内容也受到保护的期望。

  • 实例变量和容器中的项目(例如在Arrays 和Strings 中)是单独的变量,如果您发送容器,您可以直接更改其内容,因为您发送了对容器的引用,并且其中包含相同的变量用于其内容。我认为这就是您所说的“似乎是传递参考”的意思

  • 一些类——包括那些代表数字的类和Symbol——是不可变的,即没有数字的就地改变方法4。但是从概念上讲,您仍然将对单个对象的引用传递给4例程(在后台,为了提高效率,Ruby 将4在变量的内存分配中简单地编码值,但这是一个实现细节 - 该值也是“指针”在这种情况下)。

  • 接近您似乎正在寻找的“按值传递”语义的最简单方法SampleModuleclone在例程开始时使用参数。请注意,这实际上并不会导致 Ruby 更改调用语义,只是在这种情况下,您可以从方法外部获得您似乎想要的安全假设(方法内的参数发生的任何事情都保留在方法内):


module SampleModule
  def self.testing(o)
    o = o.clone
    o.test
  end
end
  • 从技术上讲,这应该是一个通用的深层克隆,但这并不需要让您的示例接近按值传递。您可以调用SampleModule.testing( any_var_or_expression )并知道any_var_or_expression其余代码中的任何内容都不会更改关联的对象。
于 2013-11-09T12:16:19.800 回答
2

如果你真的想在词汇上有所了解,Ruby 按值传递对(可变)对象的引用:

def pass_it(obj)
  obj = 'by reference'
end

def mutate_it(obj)
  obj << ' mutated'
end

str = 'by value'

pass_it(str)
mutate_it(str)

puts str # by value mutated

您可以使用dupor clone(注意两者都做浅拷贝)和freeze.

于 2013-11-09T14:48:26.380 回答
-1

Ruby 中的所有内容都是通过引用传递的:

class Test
  attr_reader :a
  def initialize(a)
    @a = a
  end
end

s = "foo"
o = Test.new(s)
o.a << "bar"
o.a          #=> "foobar"
s            #=> "foobar"
o.a.equal? s #=> true

在您的代码中,将对象传递给模块方法这一事实并没有改变任何东西;sample_object已经是对新对象的引用SampleClass.new(2)

于 2013-11-09T12:14:22.393 回答