Zrozumienie ’ ja ’ w Ruby

dzisiaj chciałbym porozmawiać o self. Jeśli programujesz Ruby od jakiegoś czasu, prawdopodobnie zinternalizowałeś ideę self. Ilekroć czytasz lub piszesz program, self jest z tyłu twojego umysłu.

ale dla mniej doświadczonych Rubyistów self może być zaskakujące. To się zawsze zmienia, ale nigdy nie jest wyraźnie pokazane w kodzie. Po prostu musisz wiedzieć.

wiele problemów, z którymi borykają się początkujący, jest spowodowanych niezrozumieniem self. Jeśli kiedykolwiek „zgubiłeś” zmienną instancji lub zastanawiałeś się, jakie dane są widoczne dla mixina, to dlatego, że nie zrozumiałeś self w tym kontekście.

w tym poście przyjrzymy się self w różnych codziennych sytuacjach.

czym jest ja?

być może słyszałeś, że ludzie mówią, że wszystko w Ruby jest obiektem. Jeśli to prawda, oznacza to, że każdy zapisany fragment kodu „należy” do jakiegoś obiektu.

self jest zmienną specjalną, która wskazuje na obiekt, który „jest właścicielem” aktualnie wykonywanego kodu. Ruby używa self everwhere:

  • na przykład zmienne: @myvar
  • dla metody i stałego wyszukiwania
  • przy definiowaniu metod, klas i modułów.

w teorii self jest dość oczywiste. Ale w praktyce łatwo jest wyskoczyć w trudnych sytuacjach. Dlatego napisałem ten post.

przykłady jaźni

przejdziemy teraz przez kilka przykładów. Jeśli pierwsze wydają ci się zbyt proste, po prostu czytaj dalej. Stają się bardziej zaawansowane.

wewnątrz metody instancji

w poniższym kodzie reflect jest metodą instancji. Należy do obiektu, który stworzyliśmy za pomocą Ghost.new. Więc self wskazuje na ten obiekt.

class Ghost def reflect self endendg = Ghost.newg.reflect == g # => true

wewnątrz metody klasy

w tym przykładzie reflectjest metodą klasy Ghost. W przypadku metod klasowych, sama klasa „posiada” metodę. self punkty do klasy.

class Ghost def self.reflect self endendGhost.reflect == Ghost # => true

działa to tak samo z metodami „class” wewnątrz modułów. Na przykład:

module Ghost def self.reflect self endend Ghost.reflect == Ghost # => true

pamiętaj, że klasy i moduły są traktowane jako obiekty w Ruby. Więc to zachowanie nie różni się zbytnio od zachowania metody instancji, które widzieliśmy w pierwszym przykładzie.

wewnątrz definicji klasy lub modułu

jedną z cech Rubiego, która sprawia, że jest tak dobrze dopasowany do frameworków takich jak Rails, jest to, że możesz wykonać dowolny kod wewnątrz definicji klas i modułów. Kiedy umieszczasz kod wewnątrz definicji klasy/modułu, działa on tak jak każdy inny kod Ruby. Jedyną rzeczywistą różnicą jest wartość self.

jak widać poniżej, self wskazuje na klasę lub moduł, który jest w trakcie definiowania.

class Ghost self == Ghost # => trueend module Mummy self == Mummy # => trueend 

wewnątrz metod mixin

metody Mixed-in zachowują się jak „normalne” metody instancji lub klasy, jeśli chodzi o self. To ma sens. W przeciwnym razie mixin nie byłby w stanie współdziałać z klasą, do której go dodałeś.

metody instancji

mimo że metoda reflect została zdefiniowana w module, jej self jest instancją klasy, do której została zmieszana.

module Reflection def reflect self endend class Ghost include Reflectionendg = Ghost.newg.reflect == g # => true

metody klasy

kiedy my extend Klasa do mieszania w metodach klasy, self zachowuje się dokładnie tak samo jak w normalnych metodach klasy.

module Reflection def reflect self endend class Ghost extend ReflectionendGhost.reflect == Ghost # => true

wewnątrz metaclass

Prawdopodobnie widziałeś ten popularny skrót do definiowania wielu metod klas naraz.

class Ghost class << self def method1 end def method2 end endend

składnia class << foo jest całkiem ciekawa. Umożliwia dostęp do metaklasu obiektu-który jest również nazywany „klasą Singletona” lub ” eigenclass.”Planuję głębiej opisać metaklasy w przyszłym poście. Ale na razie musisz tylko wiedzieć, że metaclass jest miejscem, w którym Ruby przechowuje metody, które są unikalne dla określonego obiektu.

jeśli uzyskasz dostęp do self z wnętrza bloku class << foo, otrzymasz metaclass.

class << "test" puts self.inspectend# => #<Class:#<String:0x007f8de283bd88>

poza klasą

jeśli używasz kodu poza klasą, Ruby nadal dostarcza self. Wskazuje na „główny”, który jest przykładem Object:

puts self.inspect # => main