Wie kommt es, dass dieser Ansatz zum Erstellen einer privaten Klassenmethode funktioniert:
class Person
def self.get_name
persons_name
end
class << self
private
def persons_name
"Sam"
end
end
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name #=> raises "private method `persons_name' called for Person:Class (NoMethodError)"
Das geht aber nicht:
class Person
def self.get_name
persons_name
end
private
def self.persons_name
"Sam"
end
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
ruby
access-specifier
99 Meilen
quelle
quelle
Antworten:
private
scheint nicht zu funktionieren, wenn Sie eine Methode für ein explizites Objekt definieren (in Ihrem Fallself
). Sie könnenprivate_class_method
Klassenmethoden als privat definieren (oder wie beschrieben).Alternativ (in Ruby 2.1+) können Sie dies auch wie folgt verwenden, da eine Methodendefinition ein Symbol des Methodennamens zurückgibt:
quelle
ExiRe schrieb:
Es ist wahrscheinlich verwirrend, frustrierend mag es sein, aber ekelhaft ist es definitiv nicht.
Es ist absolut sinnvoll, wenn Sie Rubys Objektmodell und den entsprechenden Methodensuchablauf verstanden haben , insbesondere wenn Sie berücksichtigen, dass
private
es sich NICHT um einen Zugriffs- / Sichtbarkeitsmodifikator handelt, sondern um einen Methodenaufruf (mit der Klasse als Empfänger), wie hier beschrieben ... In Ruby gibt es keinen "privaten Bereich" .Um private Instanzmethoden zu definieren , rufen Sie
private
die Klasse der Instanz auf, um die Standardsichtbarkeit für nachfolgend definierte Methoden auf privat festzulegen. Daher ist es sinnvoll, private Klassenmethoden durch Aufrufenprivate
der Klasse der Klasse zu definieren, d. H. seine Metaklasse.Andere selbsternannte OO-Hauptsprachen geben Ihnen möglicherweise eine weniger verwirrende Syntax, aber Sie tauschen dies definitiv gegen ein verwirrendes und weniger konsistentes (inkonsistentes?) Objektmodell aus, ohne die Leistungsfähigkeit von Rubys Metaprogrammierfunktionen.
quelle
private_class_method :method_name
könnten Sie es tun , anstatt es zu tunprivate_class_method def method_name...
.send(private_method)
ist auch außerhalb des Objekts zugänglich.private_class_method def self.method_name
Standardmäßig sind alle Klassenmethoden öffentlich. Um sie privat zu machen, können Sie Modul # private_class_method verwenden, wie @tjwallace sie geschrieben oder anders definiert hat, als Sie es getan haben:
class << self
Öffnet die Singleton-Klasse von self, sodass Methoden für das aktuelle self-Objekt neu definiert werden können. Dies wird verwendet, um die Klassen- / Modulmethode ("statisch") zu definieren. Nur dort erhalten Sie durch das Definieren privater Methoden wirklich private Klassenmethoden.quelle
Der Vollständigkeit halber können wir auch vermeiden, private_class_method in einer separaten Zeile zu deklarieren. Ich persönlich mag diese Verwendung nicht, aber es ist gut zu wissen, dass sie existiert.
quelle
Auch ich finde Ruby (oder zumindest mein Wissen darüber) in diesem Bereich hinter der Marke zurück. Zum Beispiel macht das Folgende, was ich will, ist aber ungeschickt,
Meine Probleme mit dem obigen Code bestehen darin, dass die Ruby-Syntaxanforderungen und meine Codequalitätsmetriken zu umständlichem Code führen. Damit der Code wie gewünscht funktioniert und die Metriken beruhigt werden, muss compare () zu einer Klassenmethode gemacht werden. Da ich nicht möchte, dass es Teil der öffentlichen API der Klasse ist, muss es privat sein, aber "privat" allein funktioniert nicht. Stattdessen bin ich gezwungen, 'private_class_method' oder eine solche Problemumgehung zu verwenden. Dies erzwingt wiederum die Verwendung von 'self.class.send (: compare ...' für jede Variable, die ich in '== ()' teste. Nun, das ist etwas unhandlich.
quelle
Instanzmethoden werden in einem Klassendefinitionsblock definiert. Klassenmethoden werden als Singleton-Methoden für die Singleton-Klasse einer Klasse definiert, die informell auch als "Metaklasse" oder "Eigenklasse" bezeichnet wird.
private
ist kein Schlüsselwort, sondern eine Methode ( Modul # privat ).Dies ist ein Aufruf von method
self#private
/,A#private
der den privaten Zugriff für alle bevorstehenden Instanzmethodendefinitionen "umschaltet", bis etwas anderes umgeschaltet wird:Wie bereits erwähnt, sind Klassenmethoden wirklich Singleton-Methoden, die für die Singleton-Klasse definiert sind.
Oder verwenden Sie eine spezielle Syntax, um den Definitionskörper der anonymen Singleton-Klasse von A zu öffnen:
Der Empfänger der "Nachricht privat" - self - inside
class A
ist das Klassenobjekt A. self innerhalb desclass << A
Blocks ist ein weiteres Objekt, die Singleton-Klasse.Das folgende Beispiel ruft in Wirklichkeit zwei verschiedene Methoden auf, die als privat bezeichnet werden , wobei zwei verschiedene Empfänger oder Ziele für den Anruf verwendet werden. Im ersten Teil definieren wir eine private Instanzmethode ("für Klasse A"), im letzteren definieren wir eine private Klassenmethode (ist tatsächlich eine Singleton-Methode für das Singleton-Klassenobjekt von A).
Schreiben Sie dieses Beispiel jetzt ein wenig um:
Können Sie den Fehler sehen, den Ruby-Sprachdesigner gemacht haben? Sie schalten den privaten Zugriff für alle bevorstehenden Instanzmethoden von A um, deklarieren jedoch eine Singleton-Methode für eine andere Klasse, die Singleton-Klasse.
quelle
Ruby scheint eine schlechte Lösung zu bieten. Beginnen Sie zur Erklärung mit einem einfachen C ++ - Beispiel, das den Zugriff auf Methoden privater Klassen zeigt:
Führen Sie die oben genannten
Jetzt scheint Ruby nicht das Äquivalent zu liefern. Ich denke, Rubys Regeln lauten, dass auf private Methoden nicht mit einem Empfänger zugegriffen werden darf. Das ist,
Dies ist für private Instanzmethoden in Ordnung, verursacht jedoch Probleme mit privaten Klassenmethoden.
Ich möchte, dass Ruby so funktioniert:
Aber leider funktioniert das oben genannte nicht. Kennt jemand einen besseren Weg?
Wenn ich vor einer Methode 'send' sehe, ist dies ein klares Zeichen dafür, dass der Code die Absicht des API-Designers verletzt. In diesem Fall besteht das Design jedoch speziell darin, dass eine Instanzmethode der Klasse die private Klassenmethode aufruft.
quelle
Ab Ruby 2.3.0
quelle
private def self.second_method
vor jeder Methodennotation versucht , was bei meinem Ruby 2.3.3 nicht funktioniert hat. Aber diese Notation funktioniert bei mir.Check.second_method
auch problemlos funktionieren würde und daher nicht wirklich privat ist.private_class_method :second_method