使用现有名称创建新类

时间:2015-02-06 12:21:01

标签: ruby

我们可以创建一个类,然后创建另一个具有相同名称的类。这并不奇怪。

[1] pry(main)> class A; end
=> nil
[2] pry(main)> a = A.new
=> #<A:0x0000000bd8a008>
[3] pry(main)> A = Class.new
(pry):3: warning: already initialized constant A
(pry):1: warning: previous definition of A was here
=> A
[4] pry(main)> new_a = A.new
=> #<A:0x0000000be001e0>
[5] pry(main)> a.class.name == new_a.class.name
=> true
[6] pry(main)> a.class == new_a.class
=> false
[7] pry(main)> a.class == A
=> false
[8] pry(main)> new_a.class == A
=> true

然而,在重新定义常量后,我们得到似乎是碰撞的东西:常量Anew_a.class方法返回新类,而a.class返回原始类。这些类是不同的,但它们具有相同的名称。这个代码执行时,这怎么可能以及究竟发生了什么?

4 个答案:

答案 0 :(得分:3)

class A; end做了两件事:

  1. 它会创建一个新的类对象
  2. 它将此类对象分配给常量A
  3. 删除或重新赋值常量仅影响(2),它不会更改类对象(1)。

    Ruby在将类分配给常量时也设置类名

    A.name #=> "A"
    

    类名存储在一个特殊的实例变量中(见下文),当你检查一个类的实例时,你会看到这个名字:

    A.new
    #=> #<A:0x007febc1230848>
    #     ^
    #     |
    #     +- this is A.name
    

    类名与分配给的类的常量无关:

    B = A
    
    B.name #=> "A"
    B.new  #=> #<A:0x007febc1313e68>
    

    这就是为什么你可以创建多个具有相同名称的类。

    如何在内部存储班级名称

    Ruby将类名存储在特殊的实例变量__classpath__中。它无法从Ruby中访问,但如果您要删除此限制(我已经为此示例修补了Ruby),您可以阅读它:

    A.instance_variable_get('__classpath__') #=> "A"
    

    甚至改变它:

    a = A.new #=> #<A:0x007fe0cd03ad30>
    A.instance_variable_set('__classpath__', 'just a name')
    A.name #=> "just a name"
    a #=> #<just a name:0x007fe0cd03ad30>
    

答案 1 :(得分:2)

  

这些类不同,但它们具有相同的名称。这个代码执行时,这怎么可能以及究竟发生了什么?

当您调用某个方法时,两个不同的对象完全可以返回相同的值。对此真的没什么了不起的:

a = [1, 2]
b = 'AB'

a.size # => 2
b.size # => 2

请注意,当我致电a时,b2都会返回size,但这并不意味着ab之间存在任何关系。 {{1}}。

答案 2 :(得分:0)

就像在电话簿中有两个“John Smith”条目一样。考虑一下我们有一个班级:

class A
  def whoami
    puts 'original'
  end
end

现在让我们实例化它:

a = new A
a_frozen = new A
a.whoami
#⇒ original
a_frozen.whoami
#⇒ original

让我们修改a的eighenclass:

class << a
  def whoami
    'modified'
  end
end

a.whoami
#⇒ modified
a_frozen.whoami
#⇒ original

当然,它仍然像:

a.class.name == a_frozen.class.name == 'A'

名称​​仅限名称,仅此而已。并且不同的类实例共享相同的名称没有问题。

希望它有所帮助。

答案 3 :(得分:0)

anew_a是两个不同类的实例。 您可以使用a.classnew_a.class访问这些课程。 这些类是Class的两个实例。它们似乎具有相同的名称,它们实际上是不同的类,具有不同的方法等。

class A
  def a
  end
end

a= A.new
A = Class.new
new_a = A.new

puts a.respond_to?(:a) # => true
puts new_a.respond_to?(:a) # => false