在Ruby中,一个对象可以破坏另一个吗?
例如:
class Creature
def initialize
@energy = 1
end
attr_accessor :energy
end
class Crocodile < Creature
def eat(creature)
@energy += creature.energy
creature = nil #this does not work
end
end
fish = Creature.new
croc = Crocodile.new
croc.eat(fish)
在鳄鱼吃掉一个生物并吸收其能量后,该生物应该不再存在。但是上面的代码并没有破坏这个生物。
我知道如果我说fish = nil
,变量fish
引用的对象将被垃圾收集。但是在Crocodile的creature = nil
方法中说eat
并没有实现这一点。
从croc.eat里面,我可以说“因为变量'鱼'被传递给我,当我完成后,我会把'鱼'设置为零吗?”
我基本上采用了Chuck建议的方法,并进行了一些修改。这是我的推理:
因此,我这样做了:
@creaturelist
。 (我使用实例变量而不是类变量的原因是Creature
的任何子类也可以拥有自己的列表。)@creaturelist
并返回该生物的ID。@id
变量中记住该ID。Creature.remove(@id)
调用父类,并且唯一的引用将被删除。现在我可以这样做:
class Predator < Creature
def eat(creature)
@energy += creature.energy
creature.die
end
end
fish = Creature.new
Creature.list #shows the fish
croc = Predator.new
croc.eat(fish)
Creature.list #no more fish
当然,在这个例子中,fish
仍然指向该生物对象,因此它不是垃圾收集的。但最终,生物会根据规则被创造和互相吃掉,所以我不会单独命名它们。
答案 0 :(得分:7)
我认为问题在于你将程序本身视为这些模拟事物生存的世界,而不是模拟它。
fish = Creature.new
croc = Crocodile.new
$world = [fish, croc]
class Crocodile
def eat(creature)
@energy += creature.energy
$world.delete creature
end
end
croc.eat fish
world # [croc], now all by his lonesome, the last creature in the world :(
假设fish
变量已超出范围,就像在正确结构化的程序中一样,该对象现在很可能是垃圾。
答案 1 :(得分:2)
在任何活动范围内没有任何对它的引用之前,没有什么可以安全地进行垃圾回收。
答案 2 :(得分:1)
croc.eat(fish)会忽略croc对鱼引用的生物的引用,但请注意变量“fish”本身仍然保留对该Creature的引用,因此实例不是垃圾。
编辑:这样想一想:在鳄鱼里面,你没有钓到鱼,你会得到一份鱼的内容。 fish的值是对使用Creature.new创建的对象的引用。执行croc.eat(fish)时,该引用的副本将复制到变量creature中。所以现在鱼和生物都引用了同一个物体。
就像有一个漂浮在空中的气球,上面绑着两根绳子。鱼拿着一根绳子,生物拿着另一根绳子。当你将生物设置为nil时,它会释放它在气球上的保持力,但鱼仍然用自己的绳子固定在气球上,所以气球不会漂浮到天空中的大垃圾收集器。
编辑2:不,你不能(没有一些深刻的魔法,这将是一个非常糟糕的主意),伸手去捕鱼并消灭它对相关物体的引用。
答案 3 :(得分:0)
你不是“摧毁一个物体” - GC会为你做这件事。你说的是在一个方法中,伸手进入调用者的范围并在那里更改绑定。
如果绑定是对象的一部分,并且您传入了该对象,则可以从那里重新分配它(为零)。
答案 4 :(得分:0)
一个Ruby对象(通常)不应该销毁另一个。担心对象是否仍然存在并不是你的工作。一个例外是如果您使用数据库存储 - 您可能会关心是否删除了对象。
但总的来说,我的答案是:你不应该关心这个。 (但其他答案确实有意义。)