我不确定将对象传递给模块方法时会发生什么。对象是通过引用还是通过副本传递的?就像在这个例子中一样:
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>
似乎是传递参考。真的不清楚这个。
答案 0 :(得分:2)
Ruby中的所有变量都是对象的引用。您不能以“通过引用传递”而不是“通过引用传递”,就像在C,C ++或Perl中使用该选项一样。 Ruby实际上强制传递值,否则没有其他选择。但是,发送的值始终是对象的引用。这有点像使用C或C ++,其中所有成员变量都是指针,或使用Perl,您必须始终使用引用,即使使用简单的标量。
我认为正是这种变量与对象数据的分离让你感到困惑。
几点:
变量分配从不覆盖可能指向同一对象的其他变量。这几乎是pass-by-value的定义。但是,这不符合您对对象内容也受到保护的期望。
实例变量和容器中的项目(例如Array
和String
)是单独的变量,如果您发送容器,可以更改它的内容是直接的,因为您将引用发送到容器,并且包含其内容的相同的变量。我认为这就是你所说的“似乎是传递参考”
某些类 - 包括代表数字的类和Symbol
- 是不可变的,即数字4
没有就地更改方法。但从概念上讲,您仍然将对单个对象4
的引用传递到例程中(为了提高效率,Ruby将只在变量的内存分配中编码值4
,但这是一个实现detail - 在这种情况下,值也是“指针”)。
关闭到您使用SampleModule
寻找的“按值传递”语义的最简单方法是clone
例程的开始。请注意,这实际上并不会导致Ruby更改调用语义,只是在这种情况下,从方法的外部得到安全的假设(方法中的参数保留在方法内部),你似乎想要:
module SampleModule
def self.testing(o)
o = o.clone
o.test
end
end
SampleModule.testing( any_var_or_expression )
并知道代码的其余部分中的any_var_or_expression
,相关对象将不会更改。答案 1 :(得分: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
您可以使用dup
或clone
(请注意两者都是浅色副本)和freeze
来解决可能出现的问题。
答案 2 :(得分:-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)