4

来自 c++ 背景,我对 Ruby 中的对象分配很好奇。对于以下对象分配应考虑哪些因素(如果有):

class MyClass

  attr_accessor :a, :b

  def initialize(a, b)
    @a = a
    @b = b
  end

  def some_method
    puts "#{self.a} #{self.b}"
  end
end

m = MyClass.new("first", "last")
n = MyClass.new("pizza", "hello")

q = n
q.some_method
4

3 回答 3

12

如果您熟悉 C++,那么您可能希望将 Ruby 中的每个变量(实例或其他)视为对另一个对象的引用。由于 Ruby 中的一切都是对象,甚至nil是 NilClass 类型的对象,这在任何情况下都适用。

要确定您引用的是哪个对象,您可以使用该object_id方法进行区分。这类似于&在 C++ 中转换为指针。

考虑一下:

a = "foo"
b = a

a.object_id == b.object_id
# => true

由于a是对该字符串的引用,并且b是 的副本a,因此它们实际上是对同一对象的不同引用。

这很重要,因为修改对象的操作会同等地影响对该对象的所有引用:

a << "bar"
# => "foobar"
b
# => "foobar"

但是,创建对象的操作不会修改所有副本:

a += "baz"
# => "foobarbaz"
b
# => "foobar"

Ruby 中的许多方法都用 a!来区分就地版本和新副本版本,但情况并非总是如此,因此您必须熟悉每种方法才能确定。

通常,分配将用新引用替换旧引用,因此根据经验,=将替换旧引用。这适用于+=-=||=&&=

编辑:根据 Phrogz 关于使用ObjectSpace._id2ref(object_id)将对象标识符转换为对象的评论进行更新。

于 2011-12-01T17:44:57.057 回答
3

由于一切都是 ruby​​ 中的对象,因此分配始终是通过引用进行的。

因此,将您的类作为输入,以下将是几个操作的输出:

str = "foo"
foo = MyClass.new(str, "bar")
foo.some_method # foo bar
bar = foo
bar == foo # true
bar.some_method # foo bar
str << "bar" # strings are mutable on ruby, so str is now "foobar"
foo.some_method # foobar bar
bar.some_method # foobar bar
于 2011-12-01T17:43:30.463 回答
1

我会将其重写为:

class MyClass

  attr_accessor :a, :b

  def initialize(a, b)
    self.a = a
    self.b = b
  end

  def some_method
    puts "#{a} #{b}"
  end
end

这样,您实际上是在使用attr_accessor类中定义的 getter/setter 方法

当您分配 时q = n,q 仅引用为 n 设置的相同内存位置。不复制对象。

于 2011-12-01T17:46:06.423 回答