为什么 eigenclass 看起来如此相似,但它不等于 self.class?

发布于 2024-08-09 05:47:58 字数 569 浏览 6 评论 0 原文

我在某个地方错过了备忘录,希望你能向我解释一下。

为什么对象的特征类与 self.class 不同?

class Foo
  def initialize(symbol)
    eigenclass = class << self
      self
    end
    eigenclass.class_eval do
      attr_accessor symbol
    end
  end
end

我将 eigenclass 与 class.self 等同起来的逻辑相当简单:

class << self 是声明类方法而不是实例方法的一种方式。它是 def Foo.bar 的快捷方式。

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

我只是很困惑吗?或者,这是 Ruby 元编程的一个鬼把戏?

I've missed the memo somewhere, and I hope you'll explain this to me.

Why is the eigenclass of an object different from self.class?

class Foo
  def initialize(symbol)
    eigenclass = class << self
      self
    end
    eigenclass.class_eval do
      attr_accessor symbol
    end
  end
end

My train of logic that equates the eigenclass with class.self is rather simple:

class << self is a way of declaring class methods, rather than instance methods. It's a shortcut to def Foo.bar.

So within the reference to the class object, returning self should be identical to self.class. This is because class << self would set self to Foo.class for definition of class methods/attributes.

Am I just confused? Or, is this a sneaky trick of Ruby meta-programming?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

來不及說愛妳 2024-08-16 05:47:58

类<< self 不仅仅是声明类方法的一种方式(尽管它可以这样使用)。也许您已经看到过一些用法,例如:

class Foo
  class << self
    def a
      print "I could also have been defined as def Foo.a."
    end
  end
end

这有效,并且相当于 def Foo.a,但它的工作方式有点微妙。秘密在于,在该上下文中,self 指的是对象 Foo,该对象的类是 Class 的唯一匿名子类。这个子类称为 Fooeigenclass。因此,def aFoo 的特征类中创建了一个名为 a 的新方法,可以通过正常的方法调用语法访问: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

这个示例与上一个示例相同,尽管一开始可能很难分辨。 frob 不是在 String 类上定义的,而是在 str 的特征类上定义的,它是 String 的唯一匿名子类>。因此,str 有一个 frob 方法,但 String 的实例通常没有。我们还可以重写 String 的方法(在某些棘手的测试场景中非常有用)。

现在我们已经准备好理解您的原始示例了。在 Foo 的初始化方法中,self 引用的不是类 Foo,而是 实例代码>Foo。它的eigenclass是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.

class << self is more than just a way of declaring class methods (though it can be used that way). Probably you've seen some usage like:

class Foo
  class << self
    def a
      print "I could also have been defined as def Foo.a."
    end
  end
end

This works, and is equivalent to def Foo.a, but the way it works is a little subtle. The secret is that self, in that context, refers to the object Foo, whose class is a unique, anonymous subclass of Class. This subclass is called Foo's eigenclass. So def a creates a new method called a in Foo's eigenclass, accessible by the normal method call syntax: Foo.a.

Now let's look at a different example:

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

This example is the same as the last one, though it may be hard to tell at first. frob is defined, not on the String class, but on the eigenclass of str, a unique anonymous subclass of String. So str has a frob method, but instances of String in general do not. We could also have overridden methods of String (very useful in certain tricky testing scenarios).

Now we're equipped to understand your original example. Inside Foo's initialize method, self refers not to the class Foo, but to some particular instance of Foo. Its eigenclass is a subclass of Foo, but it is not Foo; it couldn't be, or else the trick we saw in the second example couldn't work. So to continue your example:

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.
美人如玉 2024-08-16 05:47:58

最简单的答案:特征类无法实例化。

class F
 def eigen
  class << self 
   self
  end
 end
end
F.new.eigen.new #=> TypeError: can't create instance of virtual class

The simplest answer: the eigenclass can't be instantiated.

class F
 def eigen
  class << self 
   self
  end
 end
end
F.new.eigen.new #=> TypeError: can't create instance of virtual class
揽月 2024-08-16 05:47:58

Yehuda Katz 很好地解释了“Ruby 中的元编程:一切都是为了自我"

Yehuda Katz does a pretty good job of explaining the subtleties in "Metaprogramming in Ruby: It's All About the Self"

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文