【问题标题】:Why isn't the eigenclass equivalent to self.class, when it looks so similar?当 eigenclass 看起来如此相似时,为什么它不等同于 self.class?
【发布时间】:2010-12-10 11:46:04
【问题描述】:

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

为什么对象的特征类与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 &lt;&lt; self 是一种声明类方法的方式,而不是实例方法。这是def Foo.bar 的快捷方式。

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

我只是糊涂了吗?或者,这是 Ruby 元编程的诡计?

【问题讨论】:

    标签: ruby language-features eigenclass


    【解决方案1】:

    class &lt;&lt; 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 的某个特定实例。它的特征类是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 都是所创建类的匿名子类。 f1的类是Foo的匿名子类,Foo的类是Class的匿名子类。
    • 不错的答案 :) 很多人并不像你那样清楚地理解这一点。
    • 那么从概念上讲,f1 的特征类与 f1 的实际实例有何不同。如果 f1 是唯一可以访问其 eigenclass 的方法的实例,那么 f1 和它的 eigenclass 之间的区别不会被打破吗?
    • @elju 是的,有点。真正重要的区别在于“Foo”和“f1's eigenclass”;如果你有这个,你可能没问题。
    【解决方案2】:

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

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

    【讨论】:

    • 你在这个网站上可能只有1分,但我喜欢你和你的风格。
    • 同意栏杆;这是一个很好的答案
    • 这是一个非常有见地和有用的评论 IFF 已经阅读了上面@DavidSeiler 的答案。
    • 这里的强大功能是演示引发的异常。
    【解决方案3】:

    Yehuda Katz 很好地解释了“Metaprogramming in Ruby: It's All About the Self”中的微妙之处

    【讨论】:

    • 字幕或...微妙之处? ;)
    • doh :) 感谢您发现这一点,现已修复。
    猜你喜欢
    • 2010-12-08
    • 2017-07-31
    • 2019-05-20
    • 1970-01-01
    • 2016-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多