Czym dokładnie jest klasa singleton w rubinie?

85

Czy klasa singleton w Rubim jest klasą samą w sobie? Czy to jest powód, dla którego wszystkie przedmioty należą do „klasy”? Pojęcie jest niejasne , ale wydaje mi się, że ma coś wspólnego z tym, dlaczego w ogóle mogę zdefiniować metodę klasy ( class foo; def foo.bar ...).

Jaka jest klasa singleton w Rubim?

keyofnight
źródło

Odpowiedzi:

154

Najpierw mała definicja: metoda pojedyncza to metoda zdefiniowana tylko dla pojedynczego obiektu. Przykład:

irb(main):001:0> class Foo; def method1; puts 1; end; end
=> nil
irb(main):002:0> foo = Foo.new
=> #<Foo:0xb79fa724>
irb(main):003:0> def foo.method2; puts 2; end
=> nil
irb(main):004:0> foo.method1
1
=> nil
irb(main):005:0> foo.method2
2
=> nil
irb(main):006:0> other_foo = Foo.new
=> #<Foo:0xb79f0ef4>
irb(main):007:0> other_foo.method1
1
=> nil
irb(main):008:0> other_foo.method2
NoMethodError: undefined method `method2' for #<Foo:0xb79f0ef4>
        from (irb):8

Metody instancji to metody klasy (tj. Zdefiniowane w definicji klasy). Metody klasowe są pojedynczymi metodami w Classinstancji klasy - nie są zdefiniowane w definicji klasy. Zamiast tego są zdefiniowane w klasie pojedynczej obiektu.

irb(main):009:0> Foo.method_defined? :method1
=> true
irb(main):010:0> Foo.method_defined? :method2
=> false

Otwierasz pojedynczą klasę obiektu za pomocą składni class << obj. Tutaj widzimy, że ta klasa singleton jest miejscem, w którym zdefiniowane są metody singleton:

irb(main):012:0> singleton_class = ( class << foo; self; end )
=> #<Class:#<Foo:0xb79fa724>>
irb(main):013:0> singleton_class.method_defined? :method1
=> true
irb(main):014:0> singleton_class.method_defined? :method2
=> true
irb(main):015:0> other_singleton_class = ( class << other_foo; self; end )
=> #<Class:#<Foo:0xb79f0ef4>>
irb(main):016:0> other_singleton_class.method_defined? :method1
=> true
irb(main):017:0> other_singleton_class.method_defined? :method2
=> false

Zatem alternatywnym sposobem dodawania pojedynczych metod do obiektu byłoby zdefiniowanie ich za pomocą otwartej klasy pojedynczej obiektu:

irb(main):018:0> class << foo; def method3; puts 3; end; end
=> nil
irb(main):019:0> foo.method3
3
=> nil
irb(main):022:0> Foo.method_defined? :method3
=> false

W podsumowaniu:

  • metody muszą zawsze należeć do klasy (lub: być metodami instancji jakiejś klasy)
  • normalne metody należą do klasy, w której są zdefiniowane (tj. są metodami instancji tej klasy)
  • metody klasowe są po prostu pojedynczymi metodami klasy Class
  • metody pojedyncze obiektu nie są metodami instancji klasy obiektu; są to raczej metody instancji klasy singleton obiektu.
Pistos
źródło
17
Na moim nagrobku pojawi się napis „RIP Ruby Singleton. Pistos uratował mi zdrowie psychiczne”.
rmcsharry
1
@sawa Doceniam intencje twoich zmian, ale czuję, że zmieniają one znaczenie i sposób komunikacji mojego posta trochę za bardzo, więc wycofałem twoje zmiany.
Pistos
33

Ruby zapewnia sposób definiowania metod, które są specyficzne dla konkretnego obiektu, a takie metody są znane jako metody singletonowe. Kiedy ktoś deklaruje pojedynczą metodę na obiekcie, Ruby automatycznie tworzy klasę, która przechowuje tylko pojedyncze metody. Nowo utworzona klasa nosi nazwę Singleton Class.


    foo = Array.new
    def foo.size
      "Hello World!"
    end
    foo.size  # => "Hello World!"
    foo.class # => Array
    #Create another instance of Array Class and call size method on it
    bar = Array.new
    bar.size  # => 0
Klasa pojedyncza to anonimowa klasa specyficzna dla obiektu, która jest automatycznie tworzona i wstawiana do hierarchii dziedziczenia.

singleton_methods można wywołać na obiekcie, aby uzyskać listę nazw wszystkich metod pojedynczych na obiekcie.

    foo.singleton_methods  # => [:size]
    bar.singleton_methods  # => []

Ten artykuł naprawdę pomógł mi zrozumieć klasy singleton w Rubim i zawiera dobry przykład kodu.

Bedasso
źródło
4
Chociaż ta odpowiedź ma ponad rok, a link jest pomocny, byłoby lepiej, gdybyś zamieścił najważniejsze części odpowiedzi tutaj, na tej stronie lub Twój post może zostać usunięty Zobacz często zadawane pytania, w których wspomina się o odpowiedziach, które są „niewiele więcej niż link ”. Jeśli chcesz, nadal możesz dołączyć link, ale tylko jako „odniesienie”. Odpowiedź powinna istnieć samodzielnie, bez potrzeby korzystania z łącza.
Taryn
zgadzam się z @bluefeet tutaj
Saurabh
Dzięki @bluefeet, zaktualizowałem odpowiedź, aby uwzględnić Twój komentarz.
Bedasso
7

Po prostu zaktualizuj do odpowiedzi @Pistos, od wersji 1.9.2 ruby ​​dodaj nową składnię do pobierania klasy singleton

 singleton_class = ( class << foo; self; end )

można zastąpić:

singleton_class = foo.singleton_class

https://apidock.com/ruby/Object/singleton_class

Piotr Galas
źródło
4

Najbardziej pragmatycznym / ukierunkowanym na działanie sposobem myślenia o tym (IMHO) jest: jako łańcuch dziedziczenia lub kolejność wyszukiwania / rozwiązywania metod. To zdjęcie może pomóc

http://www.klankboomklang.com/2007/11/25/modules-part-i-enter-the-include-class/

To jest r 1.9, kontrastujące z klasami wbudowanymi i zdefiniowanymi przez użytkownika: wciąż przetrawiam tę.

http://d.hatena.ne.jp/sumim/20080111/p1

Wydaje mi się również, że mylącym użyciem terminu jest „obiekt singletona”, co jest inną koncepcją. Obiekt singleton pochodzi z klasy, której metoda konstruktora / instancji została zastąpiona, dzięki czemu można przydzielić tylko jedną z tej klasy.

Gene T.
źródło
Jeden z linków nie działa. A drugi jest japoński!
Ulysse BN
0

Najprościej ujmując, klasa singleton jest specjalną klasą Ruby, która łączy się z metodami hosta zdefiniowanymi na poszczególnych obiektach. W języku ruby ​​można zdefiniować metody na poszczególnych obiektach, które są unikalne tylko dla tego obiektu. Na przykład rozważ poniższe kwestie

class User; end
user = User.new
def user.age
  "i'm a unique method"
end
user1 = User.new 
user.age #"i'm a unique method"
user1.age # NoMethodError (undefined method `age' for #<User:0x0000559c66ab7338>)

Jak widać powyżej, obiekt user1 nie reaguje na metodę „age”, ponieważ jest to metoda pojedyncza, metoda jednoznacznie zdefiniowana w obiekcie użytkownika. Aby tak się stało, Ruby tworzy specjalną klasę, zwaną klasą pojedynczą lub własną, która będzie hostować tę unikalną metodę. Możesz to sprawdzić, wykonując następujące czynności:

user.singleton_class # #<Class:#<User:0x0000559c66b47c58>>

Możesz również zapytać ruby'ego, czy metoda „age” została tutaj znaleziona, używając obiektu method, aby dowiedzieć się, gdzie zdefiniowano metodę „age”. Kiedy to zrobisz, zobaczysz, że klasa singleton ma tę metodę.

user_singleton_class = user.method(:age).owner # #<Class:#<User:0x0000559c66b47c58>>
user.method(:age).owner == user.singleton_class # true
user_singleton_class.instance_methods(false) # [:age]

Zauważ również, że jeśli chodzi o klasę pojedynczą, metody singleton są w rzeczywistości metodami instancji.

user.singleton_methods == user_singleton_class.instance_methods(false) # true
Paa Yaw
źródło