2016-02-19 41 views
0

考虑下面的一组类:Ruby为什么要将变量改变到一个类的范围之外?

class Cat 
    def initialize(value) 
    @value = value 
    end 

    def speak 
    @value.pop() 
    puts @value 
    end 
end 

speak = ["Meow","Hiss","Chirp"] 

cat = Cat.new(speak) 
cat.speak 
puts speak 

class Dog 
    def initialize(value) 
    @value = value 
    end 

    def speak 
    @value.sub!("Bark", "Woof") 
    puts @value 
    end 
end 

speak = "Bark!" 

dog = Dog.new(speak) 
dog.speak 
puts speak 

我希望下面的输出是:

Meow 
Hiss 
Meow 
Hiss 
Chirp 
Woof! 
Bark! 

它是,如果我提供@value = value.dup,但给人的感觉并不Ruby'esque

但是,我收到的输出是:

Meow 
Hiss 
Meow 
Hiss 
Woof! 
Woof! 

这是Ruby的预期行为吗?一个班是否应该修改参数创建者?我知道设置@value = value将返回相同的object_id的@valuevalue但是,如果我设置@value = 'somethingelse'不应该它创建一个新的对象,而不是更改原始对象?

+3

这是预期的行为。在Ruby中,所有对象(除了像Fixnum这样的基本类型)都通过引用传递。当传递给方法时,Ruby不会创建对象的副本。 –

+2

我最近剪了我的头发。现在,有些人认为我是“Jörg”,有些人认为我是“Mittag先生”。我的理发师认识我为“米塔格先生”。但是,尽管他只剪了“Mittag先生”的头发,认识我为“Jörg”的人也观察到我的头发被剪掉了。这跟你叫我的名字无关。有什么相关的是我改变了。 –

回答

3

是的,这是预期的行为。不,如果你想分配一个新的对象,那么你需要显式调用dupclone对象上:

@value = value.dup 

阅读有关在Ruby文档clone and dup之间的差异。

+3

是的,这是Ruby的一个重要原则之一:除非你可以正确承担对它们的所有权,否则不要破坏你给出的东西。如果您需要对参数中传入的内容进行修改,请复制一份。 – tadman