一个Ruby对象能破坏另一个吗?

时间:2009-12-23 22:54:42

标签: ruby garbage-collection

在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建议的方法,并进行了一些修改。这是我的推理:

  1. 如果没有任何变量指向某个对象,则会进行垃圾回收
  2. 如果在创建对象时,我将其添加到散列(如'x'=&gt;对象),并且不为其创建任何其他变量,然后从散列中删除该项导致垃圾收集对象
  3. 似乎合乎逻辑的是,所有生物的列表都应存储在Creature类
  4. 因此,我这样做了:

    1. 在Creature类对象上,我创建了一个哈希并将其分配给一个实例变量。我们称之为@creaturelist。 (我使用实例变量而不是类变量的原因是Creature的任何子类也可以拥有自己的列表。)
    2. 在Initialize方法中,新生物将自己交给Creature类
    3. Creature类将该生物的引用添加到@creaturelist并返回该生物的ID。
    4. 该生物会在自己的@id变量中记住该ID。
    5. 如果该生物死亡,它会使用Creature.remove(@id)调用父类,并且唯一的引用将被删除。
    6. 现在我可以这样做:

      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仍然指向该生物对象,因此它不是垃圾收集的。但最终,生物会根据规则被创造和互相吃掉,所以我不会单独命名它们。

5 个答案:

答案 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对象(通常)不应该销毁另一个。担心对象是否仍然存在并不是你的工作。一个例外是如果您使用数据库存储 - 您可能会关心是否删除了对象。

但总的来说,我的答案是:你不应该关心这个。 (但其他答案确实有意义。)