14 Stimmen

Ruby-Klassenmethoden vs. Methoden in Eigenklassen

Sind Klassenmethoden und Methoden in der Eigenklasse (oder Metaklasse) dieser Klasse nur zwei Möglichkeiten, eine Sache zu definieren?

Worin bestehen sonst die Unterschiede?

class X
  # class method
  def self.a
    "a"
  end

  # eigenclass method
  class << self
    def b
      "b"
    end
  end
end

Do X.a y X.b sich in irgendeiner Weise anders verhalten?

Ich weiß, dass ich Klassenmethoden überschreiben oder mit Aliasen versehen kann, indem ich die Eigenklasse öffne:

irb(main):031:0> class X; def self.a; "a"; end; end
=> nil
irb(main):032:0> class X; class << self; alias_method :b, :a; end; end
=> #<Class:X>
irb(main):033:0> X.a
=> "a"
irb(main):034:0> X.b
=> "a"
irb(main):035:0> class X; class << self; def a; "c"; end; end; end
=> nil
irb(main):036:0> X.a
=> "c"

11voto

Phrogz Punkte 283167

Die beiden Methoden sind gleichwertig. Die 'eigenclass'-Version ist z.B. für die Verwendung der attr_*-Methoden hilfreich:

class Foo
  @instances = []
  class << self;
    attr_reader :instances
  end
  def initialize
    self.class.instances << self
  end
end

2.times{ Foo.new }
p Foo.instances
#=> [#<Foo:0x2a3f020>, #<Foo:0x2a1a5c0>]

Sie können auch Folgendes verwenden define_singleton_method um Methoden für die Klasse zu erstellen:

Foo.define_singleton_method :bim do "bam!" end

6voto

ab217 Punkte 16398

In Ruby gibt es so etwas wie Klassenmethoden eigentlich nicht. Da in Ruby alles ein Objekt ist (einschließlich der Klassen), muss man, wenn man sagt def self.class_method definieren Sie eigentlich nur eine Singleton-Methode für die Instanz der Klasse Class . Um also Ihre Frage zu beantworten, sagen Sie

class X
  def self.a
    puts "Hi"
  end

  class << self
    def b
      puts "there"
    end
  end
end

X.a # => Hi
X.b # => there

sind zwei Arten, das Gleiche zu sagen. Diese beiden Methoden sind lediglich Singeton-Methoden (Eigen-, Meta-, Ghost- oder wie auch immer Sie sie nennen wollen), die in der Instanz Ihres Class-Objekts definiert sind, das in Ihrem Beispiel war X . Dieses Thema ist Teil der Metaprogrammierung, die ein unterhaltsames Thema ist, das Sie sich ansehen sollten, wenn Sie Ruby schon eine Weile benutzen. Die Pragmatic Programmers haben eine großartige Buch über Metaprogrammierung, die Sie sich unbedingt ansehen sollten, wenn Sie sich für das Thema interessieren.

3voto

chad_ Punkte 3590

Noch ein Nekromant hier, der diese alte Frage ausgräbt... Eine Sache, die Sie vielleicht nicht wissen, ist, dass die Markierung einer Klassenmethode als private (unter Verwendung des Schlüsselworts private anstelle von :private_class_method ) ist etwas anderes als die Kennzeichnung einer Eigenklassenmethode als solche. :

class Foo
  class << self
    def baz
      puts "Eigenclass public method."
    end

    private
    def qux
      puts "Private method on eigenclass."
    end
  end
  private
  def self.bar
    puts "Private class method."
  end
end

Foo.bar
#=> Private class method.
Foo.baz
#=> Eigenclass public method.
Foo.qux
#=> NoMethodError: private method `qux' called for Foo:Class
#   from (irb)

Das folgende Beispiel funktioniert wie das vorherige:

class Foo
  class << self
    def baz
      puts "Eigen class public method."
    end

    private
    def qux
      puts "Private method on eigenclass."
    end
  end
  def bar
    puts "Private class method."
  end
  private_class_method :bar
end
Foo.bar
#=> NoMethodError: private method `bar' called for Foo:Class
#     from (irb)
Foo.baz
#=> Eigen class public method.
Foo.qux
#=> NoMethodError: private method `qux' called for Foo:Class
#     from (irb)

1voto

BrunoF Punkte 2833

Die meisten in Ruby verwendeten Instanzmethoden sind 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 nur für ein einziges Objekt implementiert.

Es besteht ein offensichtlicher Widerspruch. Ruby speichert Methoden in Klassen und alle Methoden müssen mit einer Klasse verbunden sein. Das Objekt, auf dem eine Singleton-Methode definiert ist, ist keine Klasse (es ist eine Instanz einer Klasse). Wenn nur Klassen Methoden speichern können, wie kann dann ein Objekt eine Singleton-Methode speichern? Wenn eine Singleton-Methode erstellt wird, erstellt Ruby automatisch eine anonyme Klasse, um diese Methode zu speichern. Diese anonymen Klassen werden als Metaklassen bezeichnet, auch bekannt als Singleton-Klassen oder Eigenklassen. Die Singleton-Methode ist mit der Metaklasse verbunden, die wiederum mit dem Objekt verbunden ist, für das die Singleton-Methode definiert wurde.

Wenn mehrere Singleton-Methoden innerhalb eines einzigen Objekts definiert sind, werden sie alle in derselben Metaklasse gespeichert.

class Zen
end

z1 = Zen.new
z2 = Zen.new

def z1.say_hello  # Notice that the method name is prefixed with the object name
  puts "Hello!"
end

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

Im obigen Beispiel wurde die Methode say_hello in der Instanz z1 der Klasse Zen definiert, nicht aber in der Instanz z2.

Das folgende Beispiel zeigt eine andere Art, eine Singleton-Methode zu definieren, mit dem gleichen Ergebnis.

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 class << z1 das aktuelle self so, dass es auf die Metaklasse des z1-Objekts verweist; dann wird die Methode say_hello innerhalb der Metaklasse definiert.

Die beiden obigen Beispiele dienen zur Veranschaulichung der Funktionsweise von Singleton-Methoden. Es gibt jedoch einen einfacheren Weg, eine Singleton-Methode zu definieren: mit einer eingebauten Methode namens define_singleton_method.

class Zen
end

z1 = Zen.new
z2 = Zen.new

z1.define_singleton_method(:say_hello) { puts "Hello!" }

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

Wir haben bereits gelernt, dass Klassen auch Objekte sind (Instanzen der eingebauten Klasse Class). Wir haben auch etwas über Klassenmethoden gelernt. Klassenmethoden sind nichts anderes als Singleton-Methoden, die mit einem Klassenobjekt verbunden sind.

Ein weiteres Beispiel:

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

Alle Objekte können Metaklassen haben. Das bedeutet, dass auch Klassen Metaklassen haben können. Im obigen Beispiel modifiziert class << self self, so dass es auf die Metaklasse der Klasse Zabuton zeigt. Wenn eine Methode ohne expliziten Empfänger (die Klasse/das Objekt, auf dem die Methode definiert wird) definiert wird, wird sie implizit innerhalb des aktuellen Gültigkeitsbereichs definiert, d. h. dem aktuellen Wert von self. Die Methode stuff ist also innerhalb der Metaklasse der Klasse Zabuton definiert. Das obige Beispiel ist nur eine weitere Möglichkeit, eine Klassenmethode zu definieren.

Lesen Sie mehr unter diesen Beitrag über Ruby-Klassen .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X