klasa << własny idiom w języku Ruby

873

Co ma class << selfzrobić w Ruby ?

randombits
źródło
35
Jest bardzo fajny artykuł na ten temat napisany przez Yehuda Katza: yehudakatz.com/2009/11/15/... i Yugui: yugui.jp/articles/846
Andrei
3
Kolejny bardzo fajny artykuł tutaj: integralist.co.uk/posts/eigenclass.html
Saman Mohamadi
2
Widzę to w module, czy to coś innego? github.com/ruby/rake/blob/master/lib/rake/rake_module.rb
William Entriken
@FullDecent Nie robi to różnicy, ponieważ wszystko w Rubim jest obiektem, w tym modułami i klasami.
Aaron

Odpowiedzi:

912

Po pierwsze, class << fooskładnia otwiera fooklasę singleton (eigenclass). Pozwala to na specjalizację zachowania metod wywoływanych na tym konkretnym obiekcie.

a = 'foo'
class << a
  def inspect
    '"bar"'
  end
end
a.inspect   # => "bar"

a = 'foo'   # new object, new singleton class
a.inspect   # => "foo"

Teraz, aby odpowiedzieć na pytanie: class << selfotwiera selfsingletonową klasę, dzięki czemu można przedefiniować metody dla bieżącego selfobiektu (który wewnątrz ciała klasy lub modułu jest samą klasą lub modułem ). Zwykle służy to do definiowania metod klasy / modułu („statycznych”):

class String
  class << self
    def value_of obj
      obj.to_s
    end
  end
end

String.value_of 42   # => "42"

Można to również zapisać jako skrót:

class String
  def self.value_of obj
    obj.to_s
  end
end

Lub nawet krócej:

def String.value_of obj
  obj.to_s
end

Znajdując się w definicji funkcji, selfodnosi się do obiektu, za pomocą którego funkcja jest wywoływana. W takim przypadku class << selfotwiera klasę singleton dla tego obiektu; jednym z nich jest zaimplementowanie automatu stanów biednego człowieka:

class StateMachineExample
  def process obj
    process_hook obj
  end

private
  def process_state_1 obj
    # ...
    class << self
      alias process_hook process_state_2
    end
  end

  def process_state_2 obj
    # ...
    class << self
      alias process_hook process_state_1
    end
  end

  # Set up initial state
  alias process_hook process_state_1
end

Tak więc w powyższym przykładzie każde wystąpienie aliasu StateMachineExamplezostało process_hookprzypisane do aliasu process_state_1, ale zwróć uwagę na to, jak w tym drugim przypadku może ono przedefiniować process_hook( selftylko nie wpływając na inne StateMachineExamplewystąpienia) na process_state_2. Tak więc, za każdym razem, gdy wywołujący wywołuje processmetodę (która wywołuje funkcję redefiniowalną process_hook), zachowanie zmienia się w zależności od tego, w jakim jest stanie.

Chris Jester-Young
źródło
22
@ Jörg: +1 do edycji (szkoda, że ​​SO zapewnia możliwość głosowania nad edycjami; no cóż). To jest rzeczywiście bardziej powszechne użycie metod class << selftworzenia klas / modułów. Prawdopodobnie rozwinę to zastosowanie class << self, ponieważ jest to o wiele bardziej idiomatyczne zastosowanie.
Chris Jester-Young
4
gsub! („eigenclass”, „singleton class”), zobacz nadchodzącą metodę redmine.ruby-lang.org/repositories/revision/1?rev=27022
Marc-André Lafortune
4
To bardzo mylące, aby odnieść się do a„s singleton_classod a” s klasy (po zmianie inspect) to unikalny wariant Stringklasy. Gdyby zmienił Stringklasę singletonów , wpłynęłoby to na wszystkie inne Stringinstancje. Dziwniejsze jest to, że jeśli później ponownie otworzysz, Stringaby ponownie zdefiniować, inspectto anadal wybierzesz nowe zmiany.
Old Pro
1
@OldPro Nadal wolę nazwę eigenclass, podobnie jak (jak sądzę) Matz. Ale chyba nie zadowolić wszystkich.
Chris Jester-Young,
5
Uważam, że wyrażenie „otwiera klasę singletonową obiektu” - które czytałem już wiele razy - jest niejasne. Według mojej wiedzy nigdzie w rubinowych dokumentach nie jest „otwarcie” zdefiniowanej klasy, mimo że wszyscy wiemy, co to znaczy. Czy class << selfoznacza, że ​​cokolwiek więcej niż wartość selfjest równa klasie singletonu w zakresie bloku?
Cary Swoveland
34

Znalazłem super proste wyjaśnienie class << self, Eigenclassoraz różnego rodzaju metod.

W Ruby istnieją trzy typy metod, które można zastosować do klasy:

  1. Metody instancji
  2. Metody singletonowe
  3. Metody klasowe

Metody instancji i metody klas są prawie podobne do ich homonimów w innych językach programowania.

class Foo  
  def an_instance_method  
    puts "I am an instance method"  
  end  
  def self.a_class_method  
    puts "I am a class method"  
  end  
end

foo = Foo.new

def foo.a_singleton_method
  puts "I am a singletone method"
end

Innym sposobem uzyskania dostępu do Eigenclass(który obejmuje metody singleton) jest następująca składnia ( class <<):

foo = Foo.new

class << foo
  def a_singleton_method
    puts "I am a singleton method"
  end
end

teraz możesz zdefiniować metodę singleton, dla selfktórej Foosama klasa jest w tym kontekście:

class Foo
  class << self
    def a_singleton_and_class_method
      puts "I am a singleton method for self and a class method for Foo"
    end
  end
end
Saman Mohamadi
źródło
4
w rzeczywistości metody Singleton i metody Class są takie same, obie istnieją w klasie singleton. możesz użyć foo.singleton_class.instance_methods(false)do sprawdzenia.
Damon Yuan
22

Zazwyczaj metody instancji są metodami globalnymi. Oznacza to, że są dostępne we wszystkich instancjach klasy, w której zostały zdefiniowane. Natomiast metoda singletonu jest implementowana na jednym obiekcie.

Ruby przechowuje metody w klasach i wszystkie metody muszą być powiązane z klasą. Obiekt, w którym zdefiniowana jest metoda singleton, nie jest klasą (jest instancją klasy). Jeśli tylko klasy mogą przechowywać metody, w jaki sposób obiekt może przechowywać metodę singleton? Kiedy tworzona jest metoda singleton, Ruby automatycznie tworzy anonimową klasę do przechowywania tej metody. Te anonimowe klasy nazywane są metaklasami, znanymi również jako klasy singleton lub klasy eigenclasses. Metoda singletonu jest powiązana z metaklasą, która z kolei jest powiązana z obiektem, na którym zdefiniowano metodę singletonu.

Jeśli w jednym obiekcie zdefiniowano wiele metod singletonów, wszystkie są przechowywane w tej samej metaklasie.

class Zen
end

z1 = Zen.new
z2 = Zen.new

class << z1
  def say_hello
    puts "Hello!"
  end
end

z1.say_hello    # Output: Hello!
z2.say_hello    # Output: NoMethodError: undefined method `say_hello'…

W powyższym przykładzie klasa << z1 zmienia bieżące „ja”, aby wskazywało metaklasę obiektu z1; następnie definiuje metodę say_hello w metaklasie.

Klasy są również obiektami (instancjami wbudowanej klasy o nazwie Class). Metody klasy są niczym więcej niż metodami singletonowymi powiązanymi z obiektem klasy.

class Zabuton
  class << self
    def stuff
      puts "Stuffing zabuton…"
    end
  end
end

Wszystkie obiekty mogą mieć metaklasy. Oznacza to, że klasy mogą mieć także metaklasy. W powyższym przykładzie klasa << self modyfikuje self, więc wskazuje na metaklasę klasy Zabuton. Kiedy metoda jest zdefiniowana bez jawnego odbiornika (klasy / obiektu, na którym metoda zostanie zdefiniowana), jest ona domyślnie zdefiniowana w ramach bieżącego zakresu, to znaczy bieżącej wartości self. Dlatego metoda rzeczy jest zdefiniowana w metaklasie klasy Zabuton. Powyższy przykład jest tylko innym sposobem zdefiniowania metody klasy. IMHO, lepiej jest użyć składni def self.my_new_clas_method do zdefiniowania metod klas, ponieważ ułatwia to zrozumienie kodu. Powyższy przykład został dołączony, abyśmy rozumieli, co się dzieje, gdy natrafimy na składnię << siebie składni klasy.

Dodatkowe informacje można znaleźć w tym poście na temat klas Ruby .

BrunoFacca
źródło
15

Czym zajmuje się klasa <<:

class Hi
  self #=> Hi
  class << self #same as 'class << Hi'
    self #=> #<Class:Hi>
    self == Hi.singleton_class #=> true
  end
end

[robi self == thing.singleton_class w kontekście swojego bloku] .


Co to jest thing.singleton_class?

hi = String.new
def hi.a
end

hi.class.instance_methods.include? :a #=> false
hi.singleton_class.instance_methods.include? :a #=> true

hiobiekt dziedziczy #methodspo nim, #singleton_class.instance_methodsa następnie po nim #class.instance_methods.
Tutaj daliśmy hi„s singleton klasy metody instancji :a. Można to zrobić za pomocą klasy << hi zamiast tego.
hi„S #singleton_classma wszystkie metody instancji hi” S #classma, ewentualnie nieco więcej ( :ao).

[instancyjne metody rzeczy #class i #singleton_class mogą być stosowane bezpośrednio do rzeczy. kiedy Ruby widzi rzecz. a, najpierw szuka: definicji metody w thing.singleton_class.instance_methods, a następnie w thing.class.instance_methods]


Nawiasem mówiąc - nazywają obiektu Singleton klasy == metaklasa == eigenclass .

jeziora
źródło
3

Á sposób Singleton jest sposób, który jest zdefiniowany jedynie na pojedynczy obiekt.

Przykład:

class SomeClass
  class << self
    def test
    end
  end
end

test_obj = SomeClass.new

def test_obj.test_2
end

class << test_obj
  def test_3
  end
end

puts "Singleton's methods of SomeClass"
puts SomeClass.singleton_methods
puts '------------------------------------------'
puts "Singleton's methods of test_obj"
puts test_obj.singleton_methods

Metody Singletona w SomeClass

test


Metody singletona z test_obj

test_2

test_3

artamonovdev
źródło
1

W rzeczywistości, jeśli napiszesz jakieś rozszerzenia C dla swoich projektów Ruby, jest tak naprawdę tylko jeden sposób na zdefiniowanie metody Module.

rb_define_singleton_method

Wiem, że ten własny biznes po prostu otwiera wiele innych pytań, dzięki czemu możesz lepiej przeszukać każdą część.

Przede wszystkim obiekty.

foo = Object.new

Czy mogę stworzyć metodę foo?

Pewnie

def foo.hello
 'hello'
end

Co mam z tym zrobić?

foo.hello
 ==>"hello"

Po prostu kolejny przedmiot.

foo.methods

Otrzymasz wszystkie metody Object plus swoją nową.

def foo.self
 self
end

foo.self

Tylko obiekt foo.

Spróbuj zobaczyć, co się stanie, jeśli zrobisz foo z innych obiektów, takich jak klasa i moduł. Przykłady wszystkich odpowiedzi są fajne, ale musisz pracować z różnymi pomysłami lub koncepcjami, aby naprawdę zrozumieć, co się dzieje ze sposobem pisania kodu. Masz teraz wiele warunków do obejrzenia.

Wychowano Singleton, Class, Module, self, Object i Eigenclass, ale Ruby nie nazywa w ten sposób Modelów Obiektów. To bardziej jak Metaklasa. Richard lub __why pokazuje ci ten pomysł tutaj. http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html A jeśli cię to zaskoczy, spróbuj poszukać Ruby Object Model w poszukiwaniu. Dwa filmy, które znam na YouTube to Dave Thomas i Peter Cooper. Próbują również wyjaśnić tę koncepcję. Zdobycie go zajęło Dave'owi dużo czasu, więc nie martw się. Nadal nad tym pracuję. Po co miałbym tu być? Dziękuję za twoje pytanie. Zobacz także bibliotekę standardową. Ma moduł Singleton, tak jak FYI.

To całkiem nieźle. https://www.youtube.com/watch?v=i4uiyWA8eFk

Douglas G. Allen
źródło