Klasse << Selbstsprache in Ruby


873

Was ist class << selfin tun Rubin ?


35
Es gibt einen sehr schönen Artikel zu diesem Thema, geschrieben von Yehuda Katz: yehudakatz.com/2009/11/15/… und Yugui: yugui.jp/articles/846
Andrei

3
Ein weiterer super schöner Artikel hier: Integralist.co.uk/posts/eigenclass.html
Saman Mohamadi

2
Ich sehe das in einem Modul. Macht es das anders? github.com/ruby/rake/blob/master/lib/rake/rake_module.rb
William Entriken

@FullDecent Es macht keinen Unterschied, da alles in Ruby ein Objekt ist, das Module und Klassen enthält.
Aaron

Antworten:


912

Zunächst class << fooöffnet die Syntax die fooSingleton-Klasse (Eigenklasse). Auf diese Weise können Sie das Verhalten von Methoden spezialisieren, die für dieses bestimmte Objekt aufgerufen werden.

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

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

Um nun die Frage zu beantworten: class << selfÖffnet die selfSingleton-Klasse, sodass Methoden für das aktuelle selfObjekt neu definiert werden können (das innerhalb eines Klassen- oder Modulkörpers die Klasse oder das Modul selbst ist ). Normalerweise wird dies verwendet, um Klassen- / Modulmethoden ("statische") zu definieren:

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

String.value_of 42   # => "42"

Dies kann auch als Kurzform geschrieben werden:

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

Oder noch kürzer:

def String.value_of obj
  obj.to_s
end

selfBezieht sich innerhalb einer Funktionsdefinition auf das Objekt , mit dem die Funktion aufgerufen wird. In diesem Fall wird class << selfdie Singleton-Klasse für dieses Objekt geöffnet. Eine Verwendung davon ist die Implementierung der Zustandsmaschine eines armen Mannes:

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

Im obigen Beispiel StateMachineExamplehat process_hookalso jede Instanz von einen Alias ​​für process_state_1, aber beachten Sie, wie sie in letzterer neu definiert werden kann process_hook( selfnur um andere StateMachineExampleInstanzen nicht zu beeinflussen ) process_state_2. Jedes Mal, wenn ein Aufrufer die processMethode aufruft (die die neu definierbare Methode aufruft process_hook), ändert sich das Verhalten abhängig davon, in welchem ​​Status sie sich befindet.


22
@ Jörg: +1 für die Bearbeitung (ich wünschte, SO bietet die Möglichkeit, Änderungen zu verbessern; na ja). Dies ist in der Tat die üblichere Verwendung class << self, um Klassen- / Modulmethoden zu erstellen. Ich werde wahrscheinlich auf diese Verwendung von erweitern class << self, da dies eine viel idiomatischere Verwendung ist.
Chris Jester-Young

4
gsub! ("Eigenklasse", "Singleton-Klasse"), siehe die bevorstehende Methode redmine.ruby-lang.org/repositories/revision/1?rev=27022
Marc-André Lafortune

4
Es ist wirklich verwirrend, sich auf a's zu beziehen, singleton_classda adie Klasse (nach dem Ändern inspect) eine einzigartige Variante der StringKlasse ist. Wenn die Singleton- StringKlasse geändert würde, wären alle anderen StringInstanzen betroffen . Was noch seltsamer ist , dass , wenn Sie später wieder öffnen Stringneu zu definieren , um inspectdann aabholt noch die neuen Änderungen.
Old Pro

1
@OldPro Ich bevorzuge immer noch den Namen Eigenklasse, wie (glaube ich) auch Matz. Aber ich denke, ich kann nicht allen gefallen.
Chris Jester-Young

5
Ich finde den Ausdruck "öffnet die Singleton-Klasse eines Objekts" - den ich schon oft gelesen habe - vage. Meines Wissens "öffnet" nirgends in den Ruby-Dokumenten eine definierte Klasse, obwohl wir alle eine Vorstellung davon haben, was dies bedeutet. Bedeutet class << selfdies, dass mehr als der Wert von selfgleich der Singleton-Klasse im Bereich des Blocks gesetzt wird?
Cary Swoveland

34

Ich fand eine Super einfache Erklärung über class << self, Eigenclassund verschiedene Arten von Methoden.

In Ruby gibt es drei Arten von Methoden, die auf eine Klasse angewendet werden können:

  1. Instanzmethoden
  2. Singleton-Methoden
  3. Klassenmethoden

Instanzmethoden und Klassenmethoden ähneln fast denen in anderen Programmiersprachen.

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

Eine andere Möglichkeit, auf eine zuzugreifen Eigenclass(einschließlich Singleton-Methoden), ist die folgende Syntax ( class <<):

foo = Foo.new

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

Jetzt können Sie eine Singleton-Methode definieren, für selfdie Fooin diesem Kontext die Klasse selbst ist:

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

4
Tatsächlich sind Singleton-Methoden und Klassenmethoden identisch, die beide in der Singleton-Klasse vorhanden sind. Sie können verwenden foo.singleton_class.instance_methods(false), um zu überprüfen.
Damon Yuan

22

Normalerweise sind Instanzmethoden globale Methoden. Das heißt, sie sind in allen Instanzen der Klasse verfügbar, für die sie definiert wurden. Im Gegensatz dazu ist eine Singleton-Methode für ein einzelnes Objekt implementiert.

Ruby speichert Methoden in Klassen und alle Methoden müssen einer Klasse zugeordnet sein. Das Objekt, für das eine Singleton-Methode definiert ist, ist keine Klasse (es ist eine Instanz einer Klasse). Wenn nur Klassen Methoden speichern können, wie kann ein Objekt eine Singleton-Methode speichern? Wenn eine Singleton-Methode erstellt wird, erstellt Ruby automatisch eine anonyme Klasse zum Speichern dieser Methode. Diese anonymen Klassen werden als Metaklassen bezeichnet, die auch als Singleton-Klassen oder Eigenklassen bezeichnet werden. Die Singleton-Methode ist der Metaklasse zugeordnet, die wiederum dem Objekt zugeordnet ist, für das die Singleton-Methode definiert wurde.

Wenn mehrere Singleton-Methoden in einem einzelnen Objekt definiert sind, werden sie alle in derselben Metaklasse gespeichert.

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'…

Im obigen Beispiel ändert die Klasse << z1 das aktuelle Selbst so, dass es auf die Metaklasse des z1-Objekts zeigt. Anschließend wird die say_hello-Methode innerhalb der Metaklasse definiert.

Klassen sind auch Objekte (Instanzen der integrierten Klasse namens Class). Klassenmethoden sind nichts anderes als Singleton-Methoden, die einem Klassenobjekt zugeordnet sind.

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

Alle Objekte können Metaklassen haben. Das bedeutet, dass Klassen auch Metaklassen haben können. Im obigen Beispiel ändert class << self self so, dass es auf die Metaklasse der Zabuton-Klasse verweist. Wenn eine Methode ohne expliziten Empfänger definiert wird (die Klasse / das Objekt, für die / das die Methode definiert wird), wird sie implizit innerhalb des aktuellen Bereichs definiert, dh des aktuellen Werts von self. Daher ist die Stuff-Methode in der Metaklasse der Zabuton-Klasse definiert. Das obige Beispiel ist nur eine andere Möglichkeit, eine Klassenmethode zu definieren. IMHO ist es besser, die Syntax def self.my_new_clas_method zu verwenden, um Klassenmethoden zu definieren, da dies den Code verständlicher macht. Das obige Beispiel wurde aufgenommen, damit wir verstehen, was passiert, wenn wir auf die Selbstsyntax der Klasse << stoßen.

Weitere Informationen zu Ruby-Klassen finden Sie in diesem Beitrag .


15

Welche Klasse << macht was:

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

[es macht self == thing.singleton_class im Kontext seines Blocks] .


Was ist 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

hiObjekt erbt sein #methodsvon seinem #singleton_class.instance_methodsund dann von seinem #class.instance_methods.
Hier haben wir hi‚s Singletonklasse Instanzmethode :a. Es hätte stattdessen mit der Klasse << hi gemacht werden können.
hi's #singleton_classhat alle Instanzmethoden hi' s #classund möglicherweise noch einige mehr ( :ahier).

[Instanzmethoden von Dingen #class und #singleton_class können direkt auf Dinge angewendet werden. Wenn Ruby thing.a sieht, sucht er zuerst nach: einer Methodendefinition in thing.singleton_class.instance_methods und dann in thing.class.instance_methods]


By the way - nennen sie das Objekt Singletonklasse == metaclass == Eigenklasse .


3

А Die Singleton-Methode ist eine Methode, die nur für ein einzelnes Objekt definiert ist.

Beispiel:

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

Singletons Methoden von SomeClass

Prüfung


Singletons Methoden von test_obj

test_2

test_3


1

Wenn Sie C-Erweiterungen für Ihre Ruby-Projekte schreiben, gibt es nur eine Möglichkeit, eine Modulmethode zu definieren.

rb_define_singleton_method

Ich weiß, dass dieses Selbstgeschäft einfach alle möglichen anderen Fragen aufwirft, damit Sie es besser machen können, indem Sie jedes Teil durchsuchen.

Objekte zuerst.

foo = Object.new

Kann ich eine Methode für foo erstellen?

Sicher

def foo.hello
 'hello'
end

Was mache ich damit?

foo.hello
 ==>"hello"

Nur ein weiteres Objekt.

foo.methods

Sie erhalten alle Objektmethoden sowie Ihre neue.

def foo.self
 self
end

foo.self

Nur das foo Objekt.

Versuchen Sie zu sehen, was passiert, wenn Sie aus anderen Objekten wie Klasse und Modul foo machen. Die Beispiele aus allen Antworten sind schön zu spielen, aber Sie müssen mit verschiedenen Ideen oder Konzepten arbeiten, um wirklich zu verstehen, was mit der Art und Weise, wie der Code geschrieben wird, vor sich geht. Jetzt müssen Sie sich also viele Begriffe ansehen.

Singleton, Class, Module, Self, Object und Eigenclass wurden aufgerufen, aber Ruby nennt Objektmodelle nicht so. Es ist eher wie Metaclass. Richard oder __why zeigt Ihnen die Idee hier. http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html Und wenn Sie das umhauen, versuchen Sie, Ruby Object Model bei der Suche nachzuschlagen. Zwei Videos, die ich auf YouTube kenne, sind Dave Thomas und Peter Cooper. Sie versuchen auch dieses Konzept zu erklären. Dave hat lange gebraucht, um es zu bekommen, also mach dir keine Sorgen. Ich arbeite auch noch daran. Warum sollte ich sonst hier sein? Danke für deine Frage. Schauen Sie sich auch die Standardbibliothek an. Es hat ein Singleton-Modul nur als FYI.

Das ist ziemlich gut. https://www.youtube.com/watch?v=i4uiyWA8eFk

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.