Why isn't the eigenclass equivalent to self.class, when it looks so similar?

后端 未结 3 1635
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-11-28 01:21

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?

cl         


        
相关标签:
3条回答
  • 2020-11-28 02:07

    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
    
    0 讨论(0)
  • 2020-11-28 02:08

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

    0 讨论(0)
  • 2020-11-28 02:10

    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.
    

    Hope this helps.

    0 讨论(0)
提交回复
热议问题