Pytanie Dlaczego eigenclass nie jest odpowiednikiem self.class, kiedy wygląda tak podobnie?


Tęskniłem za notatką gdzieś i mam nadzieję, że mi to wyjaśnisz.

Dlaczego eigenclass obiektu różni się od self.class?

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

Mój układ logiczny, który równoważy eigenclass class.self jest raczej prosty:

class << self jest sposobem deklarowania metod klas, a nie metod instancji. To skrót do def Foo.bar.

Więc w ramach odniesienia do obiektu klasy, powracając self powinien być identyczny z self.class. To dlatego, że class << self ustawił self do Foo.class do definicji metod / atrybutów klas.

Czy jestem po prostu zdezorientowany? Czy jest to podstępna sztuczka meta-programowania Ruby?


76
2017-10-27 13:31


pochodzenie




Odpowiedzi:


class << self jest czymś więcej niż sposobem deklarowania metod klasowych (choć może być używany w ten sposób). Prawdopodobnie widziałeś niektóre zastosowania, takie jak:

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

Działa to i jest równoważne def Foo.a, ale sposób, w jaki działa, jest trochę subtelny. Sekret jest taki selfw tym kontekście odnosi się do obiektu Foo, którego klasa jest unikalną, anonimową podklasą Class. Ta podklasa jest wywoływana Foo„s eigenclass. Więc def a tworzy nową metodę o nazwie a w Foo's eigenclass, dostępny przez normalną składnię wywołania metody: Foo.a.

Teraz spójrzmy na inny przykład:

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

Ten przykład jest taki sam jak poprzedni, chociaż początkowo może być trudny do ustalenia. frob jest zdefiniowany, a nie na String klasa, ale na poziomie str, unikalna anonimowa podklasa String. Więc str ma frob metoda, ale instancje String na ogół nie. Mogliśmy także zastąpić metody String (bardzo przydatne w niektórych trudnych scenariuszach testowych).

Teraz jesteśmy przygotowani, aby zrozumieć twój oryginalny przykład. Wewnątrz Foometoda inicjalizacji, self odnosi się nie do klasy Foo, ale do jakiegoś szczególnego instancja z Foo. Jego eigenclass jest podklasą Foo, ale to nie jest Foo; to niemożliwe, albo sztuczka, którą widzieliśmy w drugim przykładzie, nie mogła działać. Aby kontynuować przykład:

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.

Mam nadzieję że to pomoże.


114
2017-10-27 13:59



Każda instancja klasa jest anonimową podklasą utworzonej klasy. Klasa f1 to anonimowa podklasa Foo, klasa Foo to anonimowa podklasa klasy. - David Seiler
dobra odpowiedź :) wielu ludzi nie rozumie tego tak wyraźnie, jak ty. - horseyguy
Nigdy tego naprawdę nie rozumiałem, dopóki nie przeczytam twojej odpowiedzi! :) - Nikki Erwin Ramirez
Jak jest eigenclass f1 różni się wtedy, konceptualnie, od faktycznego wystąpienia f1. Jeśli f1 jest jedyną instancją, która kiedykolwiek będzie miała dostęp do metod jej eigenclass, to czy rozróżnienie między f1 a jej typem przełamania nie jest zepsute? - elju
@elju Tak, trochę. Naprawdę ważne rozróżnienie między "Foo" i "f1's eigenclass"; jeśli to masz, prawdopodobnie masz się dobrze. - David Seiler


Najprostsza odpowiedź: nie można utworzyć instancji eigenclass.

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

44
2017-11-16 16:09



możesz mieć tylko 1 punkt na tej stronie, ale lubię ciebie i twój styl. - horseyguy
Zgadzam się z poręczą; to jest świetna odpowiedź - Christopher Scott
Interesujące informacje, ale nie odpowiadaj na pytanie - Alexey
Jest to niezwykle wnikliwy i pomocny komentarz, który IFF już przeczytał powyżej. - Jazz
Władza Theo demonstruje wyjątek, który został podniesiony. - New Alexandria


Yehuda Katz robi całkiem niezłą robotę wyjaśniając subtelności w "Metaprogramowanie w Ruby: To wszystko o jaźni"


11
2017-12-21 01:38



napisy czy ... subtelności? ;) - horseyguy
doh :) Dzięki za spostrzeżenie, teraz naprawione. - Pete Hodgson
Naprawione nie - Kamil Lelonek