it-swarm.com.de

Was ist attr_accessor in Ruby?

Ich habe Schwierigkeiten, attr_accessor in Ruby zu verstehen. Kann mir das jemand erklären?

923
dennismonsewicz

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. 

2156
Max Chernyak

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 classkeine 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:

  1. 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.

  2. 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".

117
user166390

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
64
Phrogz

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

36
efalcao

Grundsätzlich fälschen sie öffentlich zugängliche Datenattribute, die Ruby nicht hat.

19
Tyler Eaves

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
17
Chuck

Einfache Erklärung ohne Code

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

  • Wenn Sie sich jedoch bereits in der CIA befunden haben , können Sie Ihren CIA-Mitarbeiter in Kabul problemlos anrufen, da diese Informationen leicht zugänglich sind, sofern Sie sich bereits in der CIA befinden. Aber wenn Sie außerhalb der CIA sind, wird Ihnen einfach kein Zugriff gewährt: Sie können nicht wissen, wer sie sind (Lesezugriff), und Sie können nicht ihre Mission zu ändern (Schreibzugriff).

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.

14
BKSpurgeon

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.

12
Jbur43

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"
11
Ahmed 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.

10
Ben

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.

7
Marcus Thornton

Einfach attr-accessor erstellt die getter- und setter-Methoden für die angegebenen Attribute

5
Veeru

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
4
Iggy

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=]
2
Praveen_Shukla

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

1

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
0
Adverbly

Attribute und Zugriffsmethoden

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.

0
BrunoFacca