【问题标题】:Can one Ruby object destroy another?一个 Ruby 对象可以摧毁另一个对象吗?
【发布时间】:2009-12-23 22:54:41
【问题描述】:

在 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 的 eat 方法中说 creature = nil 并不能做到这一点。

另一种说法

在 croc.eat 中,我可以说“既然变量 'fish' 已传递给我,当我完成后,我要将 'fish' 设置为 nil 吗?”

更新:问题已解决

我基本上采用了 Chuck 建议的方法,但做了一些修改。这是我的推理:

  1. 如果不再有任何变量指向一个对象,它将被垃圾回收
  2. 如果在创建一个对象时,我将它添加到一个散列(如 'x' => 对象),并且不为其创建任何其他变量,然后从散列中删除该项目会导致垃圾收集对象
  3. 将所有生物的列表存储在 Creature 类中似乎是合乎逻辑的

因此,我这样做了:

  1. 在 Creature 类对象上,我创建了一个哈希并将其分配给一个实例变量。我们称之为@creaturelist。 (我使用实例变量而不是类变量的原因是Creature 的任何子类也可以有自己的列表。)
  2. 在 Initialize 方法中,新生物将自己交给 Creature 类
  3. Creature 类将对该生物的引用添加到@creaturelist,并为该生物返回一个 ID。
  4. 该生物会在其自己的 @id 变量中记住该 ID。
  5. 如果该生物死亡,它会使用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 仍然指向那个生物对象,所以它不会被垃圾回收。但最终,生物会根据规则被创造出来并互相吃掉,所以我不会单独命名它们。

【问题讨论】:

  • 感谢大家帮助我更好地了解可能性。 :)

标签: ruby garbage-collection


【解决方案1】:

我认为问题在于您将程序本身视为这些模拟事物生活的世界,而不是模拟一个。

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 变量已经超出范围,就像在结构合理的程序中一样,那么该对象现在很可能是垃圾。

【讨论】:

  • 谢谢!我根据您的建议用一种方法更新了我的问题。
【解决方案2】:

在任何活动范围内没有对它的引用之前,没有任何东西可以安全地进行垃圾收集。

【讨论】:

  • 正确 - 示例代码是(不正确的)尝试删除对该对象的唯一引用。
  • 如果您有合法的需要这样做,那么您可能不应该使用指针机制对您隐藏的高级脚本语言。
【解决方案3】:

croc.eat(fish) 将清除 croc 对 fish 引用的 Creature 的引用,但请注意变量“fish”本身仍然持有对该 Creature 的引用,因此该实例不是垃圾。

edit:这样想:在鳄鱼内部,你没有得到鱼,你得到的是鱼内部的副本。 fish 的值是对您使用 Creature.new 创建的对象的引用。当您执行 croc.eat(fish) 时,该引用的副本会复制到变量 bio 中。所以现在鱼和生物都引用了同一个对象。

就像有一个气球漂浮在空中,上面系着两根绳子。鱼拿着一根绳子,而生物拿着另一根绳子。当你将 bio 设置为 nil 时,它会释放对气球的控制,但鱼仍然通过自己的绳子抓住气球,所以气球不会飘到天空中的大型垃圾收集器。

编辑 2:不,你不能(如果没有一些深奥的魔法,这将是一个非常糟糕的主意),伸手去钓鱼并清除它对相关对象的引用。

【讨论】:

  • 从 croc.eat 内部,我可以说“既然变量 'fish' 已传递给我,当我完成后,我要将 'fish' 设置为 nil 吗?”跨度>
  • @Nathan:如果没有一些非常神秘和不明智的黑客行为,您将无法影响另一个绑定中的局部变量。请记住,变量不会被传递,存储在其中的对象是。变量只是对对象的引用。
【解决方案4】:

您不是在“销毁一个对象”——GC 会为您做到这一点。您正在谈论的是在一个方法中,并进入调用者的范围并在那里更改绑定。

如果绑定是对象的一部分,并且您将对象传入,则可以从那里重新分配它(为 nil)。

【讨论】:

    【解决方案5】:

    一个 Ruby 对象(通常)不应该破坏另一个。担心对象是否仍然存在并不是您的工作。一个例外是如果您使用的是数据库存储 - 您可能会关心对象是否被删除。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-09
      • 2020-03-01
      • 2013-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多