Ich habe Schwierigkeiten, attr_accessor
in Ruby zu verstehen. Kann mir das jemand erklären?
Nehmen wir an, Sie haben eine Klasse Person
.
class Person
end
person = Person.new
person.name # => no method error
Natürlich haben wir niemals die Methode name
definiert. Lass uns das tun.
class Person
def name
@name # simply returning an instance variable @name
end
end
person = Person.new
person.name # => nil
person.name = "Dennis" # => no method error
Aha, wir können den Namen lesen, aber das bedeutet nicht, dass wir den Namen vergeben können. Das sind zwei verschiedene Methoden. Ersteres heißtreaderund letztereswriter. Wir haben den Autor noch nicht erstellt, also machen wir das.
class Person
def name
@name
end
def name=(str)
@name = str
end
end
person = Person.new
person.name = 'Dennis'
person.name # => "Dennis"
Genial. Jetzt können wir die Instanzvariable @name
schreiben und lesen, indem wir die Lese- und Schreibmethoden verwenden. Abgesehen davon, dass dies so häufig gemacht wird, warum es Zeit verschwendet, diese Methoden jedes Mal zu schreiben? Wir können es einfacher machen.
class Person
attr_reader :name
attr_writer :name
end
Auch das kann sich wiederholen. Wenn Sie Leser und Schreiber wollen, verwenden Sie einfach accessor!
class Person
attr_accessor :name
end
person = Person.new
person.name = "Dennis"
person.name # => "Dennis"
Funktioniert genauso! Und raten Sie mal, was: Die Instanzvariable @name
in unserem Personenobjekt wird genau wie bei der manuellen Ausführung gesetzt, sodass Sie sie in anderen Methoden verwenden können.
class Person
attr_accessor :name
def greeting
"Hello #{@name}"
end
end
person = Person.new
person.name = "Dennis"
person.greeting # => "Hello Dennis"
Das ist es. Um zu verstehen, wie attr_reader
-, attr_writer
- und attr_accessor
-Methoden tatsächlich Methoden für Sie generieren, lesen Sie andere Antworten, Bücher und Ruby-Dokumente.
attr_accessor ist nur eine Methode. (Der Link sollte mehr Einblick in seine Funktionsweise geben - schauen Sie sich die generierten Methodenpaare an, und ein Tutorial sollte Ihnen zeigen, wie man es benutzt.)
Der Trick ist, dass class
keine Definition in Ruby ist (es ist "nur eine Definition" in Sprachen wie C++ und Java), aber es ist ein -Ausdruck, der auswertet. Während dieser Auswertung wird beim Aufruf der attr_accessor
-Methode die aktuelle Klasse geändert. Beachten Sie den impliziten Empfänger: self.attr_accessor
, wobei self
an dieser Stelle das "offene" Klassenobjekt ist.
Das Bedürfnis nach attr_accessor
und Freunden ist gut:
Wie Smalltalk erlaubt Ruby nicht den Zugriff auf Instanzvariablen außerhalb von Methoden1 für dieses Objekt. Das heißt, auf Instanzvariablen kann nicht in der x.y
-Form zugegriffen werden, wie dies beispielsweise in Java oder Python üblich ist. In Ruby wird y
immer als zu sendende Nachricht (oder "zu rufende Methode") verwendet. Daher erzeugen die attr_*
-Methoden Wrapper, auf die die Instanz @variable
über dynamisch erstellte Methoden zugreifen kann.
Boilerplate saugt
Hoffe, das klärt einige der kleinen Details. Glückliche Kodierung.
1 Dies ist nicht unbedingt richtig und es gibt einige "Techniken" um dieses , aber es gibt keine Syntaxunterstützung für den Zugriff auf "öffentliche Instanzvariable".
attr_accessor
ist (wie in @pst angegeben) nur eine Methode. Was es tut, ist mehr Methoden für Sie zu erstellen.
Also diesen Code hier:
class Foo
attr_accessor :bar
end
ist äquivalent zu diesem Code:
class Foo
def bar
@bar
end
def bar=( new_value )
@bar = new_value
end
end
Sie können diese Art von Methode selbst in Ruby schreiben:
class Module
def var( method_name )
inst_variable_name = "@#{method_name}".to_sym
define_method method_name do
instance_variable_get inst_variable_name
end
define_method "#{method_name}=" do |new_value|
instance_variable_set inst_variable_name, new_value
end
end
end
class Foo
var :bar
end
f = Foo.new
p f.bar #=> nil
f.bar = 42
p f.bar #=> 42
attr_accessor
ist sehr einfach:
attr_accessor :foo
ist eine Abkürzung für:
def foo=(val)
@foo = val
end
def foo
@foo
end
es ist nichts weiter als ein Getter/Setter für ein Objekt
Grundsätzlich fälschen sie öffentlich zugängliche Datenattribute, die Ruby nicht hat.
Es ist nur eine Methode, die Getter- und Setter-Methoden für Instanzvariablen definiert. Eine Beispielimplementierung wäre:
def self.attr_accessor(*names)
names.each do |name|
define_method(name) {instance_variable_get("@#{name}")} # This is the getter
define_method("#{name}=") {|arg| instance_variable_set("@#{name}", arg)} # This is the setter
end
end
Die meisten der oben genannten Antworten verwenden Code. Diese Erklärung versucht, ohne Verwendung einer Analogie/Geschichte zu antworten:
Externe Parteien können nicht auf interne CIA-Geheimnisse zugreifen
Stellen wir uns einen wirklich geheimen Ort vor: die CIA. Niemand weiß, was in der CIA passiert, außer den Leuten in der CIA. Mit anderen Worten, externe Personen können nicht auf Informationen in der CIA zugreifen. Aber weil es nicht gut ist, eine Organisation zu haben, die völlig geheim ist, werden bestimmte Informationen der Außenwelt zur Verfügung gestellt - nur Dinge, von denen die CIA natürlich möchte, dass jeder etwas weiß: z. der Direktor der CIA, wie umweltfreundlich diese Abteilung im Vergleich zu allen anderen Regierungsabteilungen usw. ist. Weitere Informationen: z. Wer sind seine verdeckten Agenten im Irak oder in Afghanistan - diese Art von Dingen wird wahrscheinlich ein Geheimnis für die nächsten 150 Jahre bleiben.
Wenn Sie sich außerhalb der CIA befinden, können Sie nur auf die Informationen zugreifen, die sie der Öffentlichkeit zur Verfügung gestellt haben. Oder um die CIA-Sprache zu verwenden, können Sie nur auf Informationen zugreifen, die "gelöscht" wurden.
Die Informationen, die die CIA der Öffentlichkeit außerhalb der CIA zur Verfügung stellen möchte, werden als Attribute bezeichnet.
Die Bedeutung von Lese- und Schreibattributen:
Im Fall der CIA sind die meisten Attribute "schreibgeschützt". Das bedeutet, wenn Sie eine Partei außerhalb der CIA sind , können Sie fragen: "Wer ist der Direktor der CIA?" und Sie erhalten eine klare Antwort. Was Sie jedoch nicht mit "schreibgeschützten" Attributen tun können , sind Änderungen an der CIA. z.B. Sie können nicht telefonieren und entscheiden plötzlich , dass Kim Kardashian der Direktor sein soll oder dass Paris Hilton der Oberbefehlshaber sein soll.
Wenn die Attribute Ihnen "Schreibzugriff" gewähren, können Sie Änderungen vornehmen, wenn Sie möchten, auch wenn Sie sich außerhalb befinden. Ansonsten können Sie nur lesen.
Mit anderen Worten, Accessoren ermöglichen es Ihnen, Anfragen an Organisationen zu richten oder Änderungen daran vorzunehmen, die ansonsten keine externen Personen zulassen, je nachdem, ob die Accessoren Lese- oder Schreib-Accessoren sind.
Objekte innerhalb einer Klasse können problemlos aufeinander zugreifen
Genau dasselbe gilt für Klassen und Ihre Fähigkeit, auf darin enthaltene Variablen, Eigenschaften und Methoden zuzugreifen. HTH! Haben Sie Fragen, bitte fragen Sie und ich hoffe, ich kann klären.
Ich stand auch vor diesem Problem und schrieb eine etwas längere Antwort auf diese Frage. Es gibt bereits einige großartige Antworten, aber wenn Sie weitere Informationen wünschen, hoffe ich, dass meine Antwort helfen kann
Methode initialisieren
Mit Initialize können Sie Daten bei der Erstellung der Instanz auf eine Instanz eines Objekts festlegen, anstatt sie bei jeder neuen Instanz der Klasse in einer separaten Zeile in Ihrem Code festlegen zu müssen.
class Person
attr_accessor :name
def initialize(name)
@name = name
end
def greeting
"Hello #{@name}"
end
end
person = Person.new("Denis")
puts person.greeting
Im obigen Code setzen wir den Namen "Denis" mit der initialize-Methode, indem wir Dennis durch den Parameter in Initialize übergeben. Wenn wir den Namen ohne die Initialisierungsmethode festlegen wollten, könnten wir dies folgendermaßen tun:
class Person
attr_accessor :name
# def initialize(name)
# @name = name
# end
def greeting
"Hello #{name}"
end
end
person = Person.new
person.name = "Dennis"
puts person.greeting
Im obigen Code legen wir den Namen fest, indem wir die Setter-Methode attr_accessor mit person.name aufrufen, anstatt die Werte bei der Initialisierung des Objekts festzulegen.
Beide "Methoden" dieser Arbeit, aber initialisieren, spart uns Zeit und Codezeilen.
Dies ist die einzige Aufgabe des Initialisierens. Sie können beim Initialisieren nicht als Methode aufrufen. Um die Werte eines Instanzobjekts tatsächlich abzurufen, müssen Sie Getter und Setter (attr_reader (get), attr_writer (set) und attr_accessor (beide)) verwenden. Weiter unten finden Sie weitere Informationen dazu.
Getter, Setter (attr_reader, attr_writer, attr_accessor)
Getters, attr_reader: Der gesamte Zweck eines Getters besteht darin, den Wert einer bestimmten Instanzvariablen zurückzugeben. In dem folgenden Beispielcode finden Sie eine Aufschlüsselung.
class Item
def initialize(item_name, quantity)
@item_name = item_name
@quantity = quantity
end
def item_name
@item_name
end
def quantity
@quantity
end
end
example = Item.new("TV",2)
puts example.item_name
puts example.quantity
Im obigen Code rufen Sie die Methoden "item_name" und "Quantity" für die Instanz von Item "example" auf. Die Werte „put example.item_name“ und „example.quantity“ geben den Wert der Parameter, die in das „example“ übergeben wurden, zurück (oder „holen“) und zeigen sie auf dem Bildschirm an.
Glücklicherweise gibt es in Ruby eine inhärente Methode, mit der wir diesen Code präziser schreiben können. die attr_reader-Methode. Siehe den Code unten.
class Item
attr_reader :item_name, :quantity
def initialize(item_name, quantity)
@item_name = item_name
@quantity = quantity
end
end
item = Item.new("TV",2)
puts item.item_name
puts item.quantity
Diese Syntax funktioniert genauso, nur dass Sie sechs Zeilen Code sparen. Stellen Sie sich vor, Sie hätten 5 weitere Status für die Item-Klasse? Der Code würde schnell lang werden.
Setters, attr_writer: Was mich zuerst mit Setter-Methoden durchkreuzte, ist, dass es in meinen Augen eine identische Funktion wie die Initialisierungsmethode zu haben schien. Im Folgenden erkläre ich den Unterschied basierend auf meinem Verständnis.
Wie bereits erwähnt, können Sie mit der Methode initialize die Werte für eine Instanz eines Objekts bei der Objekterstellung festlegen.
Was aber, wenn Sie die Werte nach der Erstellung der Instanz später festlegen oder nach der Initialisierung ändern möchten? Dies wäre ein Szenario, in dem Sie eine Setter-Methode verwenden würden. DAS IS DER UNTERSCHIED. Sie müssen keinen bestimmten Status festlegen, wenn Sie die attr_writer-Methode anfänglich verwenden.
Der folgende Code ist ein Beispiel für die Verwendung einer Setter-Methode, um den Wert item_name für diese Instanz der Item-Klasse zu deklarieren. Beachten Sie, dass wir weiterhin die Getter-Methode attr_reader verwenden, damit wir die Werte abrufen und auf dem Bildschirm ausdrucken können, nur für den Fall, dass Sie den Code selbst testen möchten.
class Item
attr_reader :item_name
def item_name=(str)
@item_name = (str)
end
end
Der folgende Code ist ein Beispiel für die Verwendung von attr_writer, um unseren Code noch einmal zu verkürzen und Zeit zu sparen.
class Item
attr_reader :item_name
attr_writer :item_name
end
item = Item.new
puts item.item_name = "TV"
Der folgende Code ist eine Wiederholung des obigen Initialisierungsbeispiels, bei dem wir initialize verwenden, um den Objektwert von item_name bei der Erstellung festzulegen.
class Item
attr_reader :item_name
def initialize(item_name)
@item_name = item_name
end
end
item = Item.new("TV")
puts item.item_name
attr_accessor: Führt die Funktionen von attr_reader und attr_writer aus, wodurch Sie eine weitere Codezeile speichern.
Wenn Sie mit dem OOP - Konzept vertraut sind, müssen Sie sich mit der Getter- und Setter-Methode auskennen Attr_accessor macht dasselbe in Ruby.
Getter und Setter auf allgemeine Weise
class Person
def name
@name
end
def name=(str)
@name = str
end
end
person = Person.new
person.name = 'Eshaan'
person.name # => "Eshaan"
Setter-Methode
def name=(val)
@name = val
end
Getter-Methode
def name
@name
end
Getter- und Setter-Methode in Ruby
class Person
attr_accessor :name
end
person = Person.new
person.name = "Eshaan"
person.name # => "Eshaan"
Ich denke, ein Teil dessen, was neue Rubyisten/Programmierer (wie ich) verwirrt, ist:
"Warum kann ich der Instanz nicht einfach sagen, dass sie ein bestimmtes Attribut hat (z. B. Name) und diesem Attribut einen Wert in einem Durchlauf zuweisen?"
Etwas verallgemeinerter, aber so hat es für mich geklickt:
Gegeben:
class Person
end
Wir haben Person nicht als etwas definiert, das einen Namen oder andere Attribute für diese Angelegenheit haben kann.
Wenn wir dann:
baby = Person.new
... und versuche ihnen einen Namen zu geben ...
baby.name = "Ruth"
Wir erhalten einen Fehler , weil in Rubyland eine Person-Klasse eines Objekts nicht mit einem "Namen" assoziiert ist oder fähig ist ... noch nicht!
ABER wir können eine der angegebenen Methoden (siehe vorherige Antworten) verwenden, um zu sagen: "Eine Instanz einer Person-Klasse (baby
) kann jetzt ein Attribut mit dem Namen 'name' haben syntaktische Art, diesen Namen zu bekommen und festzulegen, aber es ist für uns sinnvoll, dies zu tun. "
Nochmals, diese Frage aus einem etwas anderen und allgemeineren Blickwinkel zu treffen, aber ich hoffe, dies hilft der nächsten Instanz der Klasse Person, die ihren Weg zu diesem Thread findet.
Einfach ausgedrückt definiert es einen Setter und einen Getter für die Klasse.
Beachten Sie, dass
attr_reader :v is equivalant to
def v
@v
end
attr_writer :v is equivalant to
def v=(value)
@v=value
end
So
attr_accessor :v which means
attr_reader :v; attr_writer :v
sind gleichwertig, um einen Setter und einen Getter für die Klasse zu definieren.
Einfach attr-accessor
erstellt die getter
- und setter
-Methoden für die angegebenen Attribute
Eine andere Möglichkeit, dies zu verstehen, besteht darin, herauszufinden, welchen Fehlercode er mit attr_accessor
beseitigt.
Beispiel:
class BankAccount
def initialize( account_owner )
@owner = account_owner
@balance = 0
end
def deposit( amount )
@balance = @balance + amount
end
def withdraw( amount )
@balance = @balance - amount
end
end
Folgende Methoden stehen zur Verfügung:
$ bankie = BankAccout.new("Iggy")
$ bankie
$ bankie.deposit(100)
$ bankie.withdraw(5)
Die folgenden Methoden werfen einen Fehler aus:
$ bankie.owner #undefined method `owner'...
$ bankie.balance #undefined method `balance'...
owner
und balance
sind technisch gesehen keine a-Methode, sondern ein Attribut. Die BankAccount-Klasse verfügt nicht über def owner
und def balance
. Wenn ja, können Sie die beiden folgenden Befehle verwenden. Diese beiden Methoden sind jedoch nicht vorhanden. Sie können jedoch access -Attribute so verwenden, als würden Sie access auf eine Methode über attr_accessor
!! zugreifen. Daher das Wort attr_accessor
. Attribut. Accessor. Es greift auf Attribute zu, wie Sie auf eine Methode zugreifen würden.
Durch das Hinzufügen von attr_accessor :balance, :owner
können Sie balance
und owner
"Methode" lesen und schreiben. Jetzt können Sie die letzten 2 Methoden verwenden.
$ bankie.balance
$ bankie.owner
Definiert ein benanntes Attribut für dieses Modul, wobei der Name symbol.id2name lautet, und erstellt eine Instanzvariable (@name) und eine entsprechende Zugriffsmethode, um es zu lesen. Erstellt auch eine Methode namens name =, um das Attribut festzulegen.
module Mod
attr_accessor(:one, :two)
end
Mod.instance_methods.sort #=> [:one, :one=, :two, :two=]
Um ein Attribut zusammenzufassen, gibt es unter dem Namen attr_accessor zwei kostenlose Methoden.
Wie in Java werden sie Getter und Setter genannt.
Viele Antworten haben gute Beispiele gezeigt, daher werde ich mich kurz fassen.
#the_attribute
und
# the_attribute =
In den alten Ruby-Dokumenten bedeutet ein Hashtag # eine Methode . Es könnte auch ein Klassennamenpräfix ... MyClass # my_method enthalten
Ich bin neu bei Ruby und musste mich nur mit der folgenden Verrücktheit auseinandersetzen. Könnte in Zukunft jemand anderem helfen. Am Ende ist es wie oben erwähnt, wobei zwei Funktionen (def myvar, def myvar =) implizit für den Zugriff auf @myvar erhalten werden, diese Methoden können jedoch durch lokale Deklarationen überschrieben werden.
class Foo
attr_accessor 'myvar'
def initialize
@myvar = "A"
myvar = "B"
puts @myvar # A
puts myvar # B - myvar declared above overrides myvar method
end
def test
puts @myvar # A
puts myvar # A - coming from myvar accessor
myvar = "C" # local myvar overrides accessor
puts @myvar # A
puts myvar # C
send "myvar=", "E" # not running "myvar =", but instead calls setter for @myvar
puts @myvar # E
puts myvar # C
end
end
Attribute sind Klassenkomponenten, auf die von außerhalb des Objekts zugegriffen werden kann. Sie werden in vielen anderen Programmiersprachen als Eigenschaften bezeichnet. Ihre Werte sind über die "Punktnotation" wie in object_name.attribute_name zugänglich. Im Gegensatz zu Python und einigen anderen Sprachen erlaubt Ruby keinen direkten Zugriff auf Instanzvariablen von außerhalb des Objekts.
class Car
def initialize
@wheels = 4 # This is an instance variable
end
end
c = Car.new
c.wheels # Output: NoMethodError: undefined method `wheels' for #<Car:0x00000000d43500>
Im obigen Beispiel ist c eine Instanz (Objekt) der Klasse Car. Wir haben erfolglos versucht, den Wert der Rollenvariablenvariable von außerhalb des Objekts zu lesen. Was passiert ist, ist, dass Ruby versucht hat, eine Methode namens wheels innerhalb des c-Objekts aufzurufen, es wurde jedoch keine solche Methode definiert. Kurz gesagt, object_name.attribute_name versucht, eine Methode namens attributname innerhalb des Objekts aufzurufen. Um auf den Wert der Räder-Variablen von außen zugreifen zu können, müssen wir eine Instanzmethode mit diesem Namen implementieren, die beim Aufruf den Wert dieser Variablen zurückgibt. Das nennt man eine Accessor-Methode. Im allgemeinen Programmierkontext besteht der übliche Weg, auf eine Instanzvariable von außerhalb des Objekts zuzugreifen, in der Implementierung von Zugriffsmethoden, die auch als Getter- und Setter-Methoden bezeichnet werden. Mit einem Getter kann der Wert einer innerhalb einer Klasse definierten Variablen von außen gelesen werden, und mit einem Setter kann er von außen geschrieben werden.
Im folgenden Beispiel haben wir der Klasse Car Getter- und Setter-Methoden hinzugefügt, um auf die Radvariable von außerhalb des Objekts zuzugreifen. Dies ist nicht der "Ruby-Weg", um Getter und Setter zu definieren. es dient nur zur Veranschaulichung, was Getter- und Setter-Methoden tun.
class Car
def wheels # getter method
@wheels
end
def wheels=(val) # setter method
@wheels = val
end
end
f = Car.new
f.wheels = 4 # The setter method was invoked
f.wheels # The getter method was invoked
# Output: => 4
Das obige Beispiel funktioniert und ähnlicher Code wird häufig zum Erstellen von Getter- und Setter-Methoden in anderen Sprachen verwendet. Ruby bietet jedoch eine einfachere Möglichkeit, dies zu tun: Drei integrierte Methoden, attr_reader, attr_writer und attr_acessor. Die attr_reader-Methode macht eine Instanzvariable von außen lesbar, attr_writer macht sie schreibbar und attr_acessor macht sie lesbar und schreibbar.
Das obige Beispiel kann so umgeschrieben werden.
class Car
attr_accessor :wheels
end
f = Car.new
f.wheels = 4
f.wheels # Output: => 4
Im obigen Beispiel ist das wheels-Attribut von außerhalb des Objekts lesbar und schreibbar. Wenn wir anstelle von attr_accessor attr_reader verwenden, wäre dies schreibgeschützt. Wenn wir attr_writer verwenden, wäre dies nur schreibgeschützt. Diese drei Methoden sind keine Getter und Setter in sich, sondern sie erzeugen, wenn sie aufgerufen werden, Getter- und Setter-Methoden für uns. Sie sind Methoden, die dynamisch (programmgesteuert) andere Methoden generieren. das nennt man Metaprogrammierung.
Das erste (längere) Beispiel, in dem die integrierten Methoden von Ruby nicht verwendet werden, sollte nur verwendet werden, wenn in den Getter- und Setter-Methoden zusätzlicher Code erforderlich ist. Beispielsweise muss eine Setter-Methode möglicherweise Daten validieren oder Berechnungen durchführen, bevor einer Instanzvariable ein Wert zugewiesen wird.
Sie können auf Instanzvariablen von außerhalb des Objekts zugreifen (lesen und schreiben), indem Sie die integrierten Methoden instance_variable_get und instance_variable_set verwenden. Dies ist jedoch selten zu rechtfertigen und in der Regel eine schlechte Idee, da die Umgehung der Kapselung dazu führt, dass alle möglichen Verwüstungen entstehen.