W Rubim są jakieś powiązane zastosowania składni: class
class << self
attr_accessor :n, :totalX, :totalY
end

Powyższa składnia jest używana do definiowania zmiennych instancji klasy. Ale kiedy myślę o tym, co oznacza składnia, nie ma to dla mnie żadnego sensu, więc zastanawiam się, czy ten typ składni jest używany do innych typów definicji. Mój punkt pomieszania jest taki:

class << self

Operator append zwykle oznacza "dodaj to, co znajduje się po prawej stronie do obiektu po lewej". Ale w kontekście tego bloku, jak to sumuje się do "umieścić zawartość tego bloku w definicji instancja klasy a nie instancja"?

Z tego samego powodu jestem zdezorientowany, dlaczego w jednej klasie kontekstowej

class Point
  # Instance methods go here
  class << self
    # Class methods go here
  end
end
Author: Jon Seigel, 2009-05-22

3 answers

W Rubim możesz ponownie otworzyć istniejące klasy i dodać metody. Czyli można powiedzieć:

class Foo
  def bob
    return "hello from bob"
  end
end

Te metody są przechowywane gdzieś w wewnętrznym słowniku (być może zmienna instancji) klasy Foo (która jest tylko instancją klasy Class - i dlatego mA zmienne instancji)

Ale zaskakujące jest to, że można również dodawać metody do instancji istniejących obiektów

foo = Foo.new
foo2 = Foo.new

def foo.fred
  return "I am fred"
end


foo.fred  #=> "I am fred"
foo2.fred #=> NoMethodError

Ale gdzie ta metoda faktycznie przechowywane ?

Okazuje się, że Ruby tworzy nową klasę za kulisami (czasami nazywaną klasą singleton, metaclass lub eigenclass ), który jest wstawiany do dziedziczenia heirarchii pomiędzy klasą Foo i jej instancją.

Więc relacja dziedziczenia wygląda tak:

foo < (eigenclass of foo) < Foo < Class

(Jeśli powiesz foo.superclass nie zobaczysz klasy singleton)

class << X-składnia jest sposobem na dotarcie do tej specjalnej klasy, więc że możesz nim manipulować bezpośrednio. Następujące bloki kodu są dokładnie równoważne:

def foo.bar
  return "xy"
end

# is exactly the same as

class << foo
  def bar
    return "xy"
  end
end

Więc podobieństwo między class Foo < Bar i class << Foo nie jest przypadkowe, istnieje dziedziczenie w obu.

Pomyśl o class << X jako "otwórz metaklasę X"

W Rubim należy pamiętać, że same klasy są tylko obiektami. (Instancje klasy Class) więc jeśli powiesz:

class Foo
  class << self
    def k
      return "x"
    end
  end
end

(self jest związana z Foo w tym bloku kodu), więc k jest metoda instancji z eigenclass z Foo, co czyni ją metodą klasy dla Foo

Wszystko to jest wyjaśnione dokładniej w rozdziale o klasach kilofa (wersja internetowa nie zawiera niestety diagramów) i _whys widząc Metaklasy wyraźnie

 19
Author: levinalex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-15 17:06:04

Pomyśl o klasie, która zawiera słownik członków zawierający wszystkie Accesory i zmienne instancji. Kiedy każesz klasie "dołączyć" do "siebie", mówisz " dodaj je do słownika członków klasy."

Przyznam, że notacja jest trochę dziwna.

 2
Author: Charlie Martin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-22 05:35:02

W rzeczywistości mylące jest myślenie o tym w kategoriach operatora "dołączania". lepszym sposobem na przyjrzenie się temu jest to, że tak jak class Foo otwiera klasę Foo, czyli ustawia "self" na obiekt klasy Foo, tworząc go w razie potrzeby, tak class << self otwiera eigenclass bieżącego obiektu "self". zauważ, że nie ogranicza się do self-dla dowolnego paska obiektu, można powiedzieć class

class A
  def hello
    print "hello world"
  end
end

a = A.new
b = A.new

class << a
  def goodbye
    print "goodbye cruel world"
  end
end

a.hello
b.hello
a.goodbye
b.goodbye
 1
Author: Martin DeMello,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-22 06:33:44