Почему собственный класс не эквивалентен самому себе.класс, когда это выглядит так похожи?


я где-то пропустил записку, и я надеюсь, что вы объясните мне это.

почему собственный класс объекта отличается от self.class?

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

мой поезд логики, который приравнивает собственный класс с class.self довольно проста:

class << self - это способ объявления методов класса, а не методов экземпляра. Это короткий путь к def Foo.bar.

Итак, в пределах ссылки на объект класса, возвращая self должны быть идентичны self.class. Это потому что class << self установить self до Foo.class для определения методов/атрибутов класса.

я просто запуталась? Или это хитрый трюк метапрограммирования Ruby?

3 78

3 ответа:

class << 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. Этот подкласс называется Foo ' s eigenclass. Так что def a создает новый метод a in Fooсобственный класс, доступный с помощью обычного синтаксиса вызова метода: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'ы 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.

надеюсь, что это помогает.

самый простой ответ:собственный класс не может быть создан.

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

Иегуда Кац довольно хорошо объясняет тонкости в "метапрограммирование в Ruby: это все о себе"