当它看起来如此相似时,为什么本征类不等同于self.class?

Rob*_*t K 80 ruby language-features eigenclass

我错过了某个地方的备忘录,我希望你能解释一下这个.

为什么对象的本征类不同self.class

class Foo
  def initialize(symbol)
    eigenclass = class << self
      self
    end
    eigenclass.class_eval do
      attr_accessor symbol
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

我的逻辑系列等同于特征类,class.self非常简单:

class << self是一种声明类方法的方法,而不是实例方法.这是捷径def Foo.bar.

因此在对类对象的引用中,返回self应该相同self.class.这是因为,class << self将设置selfFoo.class用于类方法的定义/属性.

我只是困惑吗?或者,这是Ruby元编程的偷偷摸摸的伎俩吗?

Dav*_*ler 121

class << self不仅仅是一种声明类方法的方法(虽然它可以这样使用).可能你看过一些用法:

class Foo
  class << self
    def a
      print "I could also have been defined as def Foo.a."
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

这有效,并且相当于def Foo.a,但它的工作方式有点微妙.秘诀在于self,在该上下文中,指的是对象Foo,其类是一个唯一的匿名子类Class.这个子类被称为Fooeigenclass.因此,def a创建一个名为ain Fooeigenclass 的新方法,可以通过常规方法调用语法访问:Foo.a.

现在让我们看一个不同的例子:

str = "abc"
other_str = "def"

class << str
  def frob
    return self + "d"
  end
end

print str.frob # => "abcd"
print other_str.frob # => raises an exception, 'frob' is not defined on other_str
Run Code Online (Sandbox Code Playgroud)

这个例子和最后一个例子相同,但最初可能很难说. frob定义,不是在String类上,而是在本征str类,一个独特的匿名子类String.所以str有一种frob方法,但String一般情况下没有.我们也可以覆盖String的方法(在某些棘手的测试场景中非常有用).

现在我们已经准备好了解您的原始示例.里面Foo的initialize方法,self指的不是班Foo,但一些特定实例Foo.它的本征类是Foo它的子类,但它不是Foo; 它不可能,否则我们在第二个例子中看到的技巧无法奏效.所以继续你的例子:

f1 = Foo.new(:weasels)
f2 = Foo.new(:monkeys)

f1.weasels = 4 # Fine
f2.monkeys = 5 # Also ok
print(f1.monkeys) # Doesn't work, f1 doesn't have a 'monkeys' method.
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.

  • 每个实例的*class*是创建的类的匿名子类.f1的类是Foo的匿名子类,Foo的类是Class的匿名子类. (20认同)
  • 很好的答案:)很多人不像你那样清楚地理解这一点. (6认同)
  • 从概念上讲,f1的本征类与f1的实际实例有何不同.如果f1是唯一可以访问其本征类方法的实例,那么f1与其本征类之间的区别是不是会分解? (3认同)
  • 在我读完你的答案之前,从来没有真正理解过 :) (2认同)

小智 46

最简单的答案:本征类无法实例化.

class F
 def eigen
  class << self 
   self
  end
 end
end
F.new.eigen.new #=> TypeError: can't create instance of virtual class
Run Code Online (Sandbox Code Playgroud)

  • 这是一个非常有见地和有帮助的评论IFF已经阅读了@ DavidSeiler上面的回答. (3认同)

Pet*_*son 11

Yehuda Katz在解释" Ruby中的元编程:一切都是关于自我 "中的细微之处方面做得非常出色

  • 字幕或...细微之处?;) (7认同)