Was ist attr_accessor in Ruby?

1023

Ich habe eine harte Zeit zu verstehen , attr_accessorin Rubin .
Kann mir das jemand erklären?

dennismonsewicz
quelle
1
Funktioniert attr_accessor in Git genauso? Ich stelle fest, dass einige Tutorials nicht genug erklären und andere Vorkenntnisse voraussetzen.
Angelfirenze
10
@ Angelfirenze, githat nichts damit zu tun attr_accessor. Git ist eine Versionskontrollsoftware, während attr_accessores sich bei Ruby um eine Methode handelt .
Usbekjon

Antworten:

2360

Angenommen, Sie haben eine Klasse Person.

class Person
end

person = Person.new
person.name # => no method error

Offensichtlich haben wir nie eine Methode definiert name. 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 zuweisen können. Das sind zwei verschiedene Methoden. Ersteres heißt Leser und letzteres Schriftsteller . 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 Instanzvariablen @namemit Lese- und Schreibmethoden schreiben und lesen . Außer, dass dies so häufig gemacht wird, warum sollte man jedes Mal Zeit damit verschwenden, diese Methoden zu schreiben? Wir können es einfacher machen.

class Person
  attr_reader :name
  attr_writer :name
end

Auch dies kann sich wiederholen. Wenn Sie sowohl Leser als auch Schreiber möchten, 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: Die Instanzvariable @namein unserem Personenobjekt wird genau wie bei der manuellen Ausführung festgelegt, 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_writerund attr_accessorMethoden tatsächlich Methoden für Sie generieren, lesen Sie andere Antworten, Bücher, Rubin docs.

Max Chernyak
quelle
46
@akunin - danke für diese klare Antwort. Was mir fehlt, ist, warum die Ruby-Syntax einen Doppelpunkt ':' für die Instanzvariablen in der attr_ * -Anweisung vorschlägt? Es scheint einfacher zu sein, dieselbe '@' - Syntax zu verwenden, die an anderer Stelle in der Klasse verwendet wird, um auf die Variable zu verweisen.
Will
207
@WilliamSmith Um Ihre Frage zu beantworten, müssen Sie verstehen, dass attr_accessores sich um eine Methode handelt, die für die aktuelle Klasse aufgerufen wird und die :nameSie an diese Methode übergeben. Es ist keine spezielle Syntax, sondern ein einfacher Methodenaufruf. Wenn Sie ihm eine @nameVariable geben würden, wäre dies nicht sinnvoll, da @name enthalten würde nil. Es wäre also wie beim Schreiben attr_accessor nil. Sie übergeben ihm keine Variable, die erstellt werden muss, sondern den Namen, unter dem die Variable aufgerufen werden soll.
Max Chernyak
23
@akunin - Das macht total Sinn. Ich habe gerade heute erfahren, dass Ruby tatsächlich "läuft", während es eine Datei analysiert, und dass jede Anweisung und jeder Ausdruck tatsächlich ein Methodenaufruf für ein Objekt ist. Einschließlich attr_accessor. Sehr hilfreich.
Will
52
benutzte Rails für 3 Jahre, wusste das noch nie. Schade
Sean Xiao
5
@Buminda ja, aber Methode nameund Variable @namesind nicht dasselbe. Verwirre sie nicht. Sie haben eine Instanzvariable @namein Ihrer Klasse und definieren attr_reader :namediese, um sie von außen lesen zu können. Ohne attr_readergibt es keine einfache Möglichkeit, @nameaußerhalb Ihrer Klasse zuzugreifen .
Max Chernyak
127

attr_accessor ist nur eine Methode . (Der Link sollte mehr Einblick in die Funktionsweise geben. Sehen Sie sich die generierten Methodenpaare an, und ein Tutorial sollte Ihnen zeigen, wie Sie ihn verwenden.)

Der Trick ist, dass classes sich nicht um eine Definition in Ruby handelt (es ist "nur eine Definition" in Sprachen wie C ++ und Java), sondern um einen Ausdruck, der ausgewertet wird . Während dieser Auswertung wird die attr_accessorMethode aufgerufen, die wiederum die aktuelle Klasse ändert. Denken Sie an den impliziten Empfänger : self.attr_accessor, wo selfsich an dieser Stelle das "offene" Klassenobjekt befindet.

Das Bedürfnis nach attr_accessorund nach Freunden ist:

  1. Ruby erlaubt wie Smalltalk nicht, auf Instanzvariablen außerhalb von Methode 1 für dieses Objekt zuzugreifen. Das heißt, auf Instanzvariablen kann nicht in der x.yForm zugegriffen werden , wie dies beispielsweise in Java oder sogar Python üblich ist. In Ruby ywird immer eine Nachricht zum Senden (oder "Methode zum Aufrufen") verwendet. Auf diese Weise attr_*erstellen die Methoden Wrapper, die den Instanzzugriff @variableüber dynamisch erstellte Methoden übertragen.

  2. Boilerplate saugt

Ich hoffe, dies verdeutlicht einige der kleinen Details. Viel Spaß beim Codieren.


1 Dies ist nicht unbedingt der Fall und es gibt einige "Techniken" , aber es gibt keine Syntaxunterstützung für den Zugriff auf "öffentliche Instanzvariablen".

Gemeinschaft
quelle
Wenn Sie sagen, attr_accessor sei "nur eine Methode", verstehe ich das. Aber was ist die Syntax verwendet , um Aufruf aufgerufen diese Methode? Ich habe Probleme, den Abschnitt in der Ruby-Dokumentation zu finden, der sich mit Syntax wie some_method: name => "was auch immer" ,: notherName ,: etc
BT
68

attr_accessorist (wie @pst sagte) nur eine Methode. Es werden mehr Methoden für Sie erstellt.

Also dieser Code hier:

class Foo
  attr_accessor :bar
end

entspricht 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
Phrogz
quelle
3
Dies ist ein großartiges Beispiel dafür, wo Metaprogrammierung selbst in Szenarien für Anfänger verwendet wird. Sehr schön.
John Simon
2
Ich habe nach einer Implementierungsskizze gesucht attr_accessorund hier endlich gefunden! Es hat zwar mein Problem gelöst, aber ich bin gespannt, wo (Buch / offizielles Dokument) ich ein solches Implementierungsbeispiel finden kann.
Wasif Hossain
40

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

efalcao
quelle
10
Ihre Antwort ist in Ordnung. 'Shortcut' bedeutet laut meinem Wörterbuch "eine kürzere alternative Route", nicht "Syntaxzucker" oder "vom Interpreter interpretiertes Makro".
Bowsersenior
25

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

Tyler Eaves
quelle
4
Obwohl dieser Kommentar nicht ganz nützlich ist, ist er wahr. Hebt die Tatsache hervor, dass öffentliche Datenattribute außerhalb der "get" -Methoden in Ruby nicht vorhanden sind. Dies ist eine sehr nützliche Information für jemanden, der versucht, die Sprache zu lernen.
Eric Dand
3
Dies sollte wirklich nicht herabgestuft werden. Als Nicht-Ruby-Typ, der versucht, dieses Zeug herauszufinden, ist diese Antwort sehr hilfreich!
Brad
1
Einverstanden, scheint dem Namen von C # sehr ähnlich zu sein {get; set;}
David Miler
17

Es ist nur eine Methode, die Getter- und Setter-Methoden für Instanzvariablen definiert. Eine beispielhafte Implementierung 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
Futter
quelle
Der Umgang mit mehreren Attributen auf diese Weise ist großartig!
Wasif Hossain
Dies war ein wirklich hilfreicher Code-Ausschnitt, um eine andere Frage zu lösen, die ich im Zusammenhang mit der Metaprogrammierung hatte.
Alexventuraio
15

Einfache Erklärung ohne Code

Die meisten der oben genannten Antworten verwenden Code. Diese Erklärung versucht, sie ohne Verwendung einer zu beantworten, und zwar über eine Analogie / Geschichte:

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 innerhalb 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, über die die CIA natürlich alle wissen lassen möchte: zB der Direktor der CIA, wie umweltfreundlich diese Abteilung verglichen wird an alle anderen Regierungsabteilungen usw. Weitere Informationen: zB wer sind seine verdeckten Agenten im Irak oder in Afghanistan - diese Art von Dingen wird wahrscheinlich für die nächsten 150 Jahre ein Geheimnis bleiben.

  • Wenn Sie sich außerhalb der CIA befinden, können Sie nur auf die Informationen zugreifen, die der Öffentlichkeit zur Verfügung gestellt wurden. Um die CIA-Sprache zu verwenden, können Sie nur auf Informationen zugreifen, die "gelöscht" sind.

  • 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 heißt, 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. Mit "schreibgeschützten" Attributen können Sie jedoch keine Änderungen an der CIA vornehmen. Sie können beispielsweise nicht telefonieren und plötzlich entscheiden , dass Kim Kardashian der Direktor sein soll oder dass Paris Hilton der Oberbefehlshaber sein soll.

  • Wenn Sie durch die Attribute Schreibzugriff erhalten, 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, mit Accessoren können Sie Anfragen an Organisationen stellen oder Änderungen vornehmen, die ansonsten keine externen Personen zulassen, je nachdem, ob es sich bei den Accessoren um Lese- oder Schreib-Accessoren handelt.

Objekte innerhalb einer Klasse können leicht aufeinander zugreifen

  • Wenn Sie sich jedoch bereits in der CIA befanden , 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. Wenn Sie sich jedoch außerhalb der CIA befinden, erhalten Sie einfach keinen Zugriff: Sie können nicht wissen, wer sie sind (Lesezugriff), und Sie können ihre Mission nicht ändern (Schreibzugriff).

Genau das Gleiche gilt für Klassen und Ihre Fähigkeit, auf Variablen, Eigenschaften und Methoden in ihnen zuzugreifen. HTH! Fragen, bitte stellen und ich hoffe, ich kann klären.

BKSpurgeon
quelle
Ihre Erklärung macht Sinn! +1 Entschuldigung, sind Sie sicher, dass der Ausdruck "Informationen, die von der CIA gelöscht werden, richtig ist?
Kouty
In der CIA gibt es verschiedene "Freigabestufen": z. B. streng geheim (niemand außer dem Prez) oder öffentliches Vertrauen (jeder kann diese Informationen lesen). Die CIA liefert tatsächlich viele sehr coole Fakten!
BKSpurgeon
Sie verdienen die Gegenstimme nur für die Beispiele von Kardashian, Paris Hilton :) Ich dachte, es wäre schon schlimm genug mit Trump als Präsident, stellen Sie sich die beiden Verantwortlichen vor, omg!
rmcsharry
Ja! Das ist was wir brauchen, StackOverflow ohne Code! :-)
Marvin
13

Wenn Sie mit dem OOP-Konzept vertraut sind, müssen Sie mit der Getter- und Setter-Methode vertraut sein. attr_accessor macht dasselbe in Ruby.

Getter und Setter im Allgemeinen

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"
Ahmed Eshaan
quelle
2
perfekte Erklärung! Es ist ein sehr praktisches Verhalten und kann zu leicht überschrieben werden.
Rubyrider
12

Ich habe mich auch diesem Problem gestellt und eine etwas längere Antwort auf diese Frage geschrieben. Es gibt bereits einige gute Antworten darauf, aber jeder, der mehr Klarheit sucht, hoffe, dass meine Antwort helfen kann

Methode initialisieren

Mit "Initialisieren" können Sie beim Erstellen der Instanz Daten für eine Instanz eines Objekts festlegen, anstatt sie jedes Mal, wenn Sie eine neue Instanz der Klasse erstellen, in einer separaten Zeile in Ihrem Code festlegen zu müssen.

class Person

  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 Initialisierungsmethode, indem wir Dennis durch den Parameter in Initialize übergeben. Wenn wir den Namen ohne die Initialisierungsmethode festlegen möchten, können 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“, um diese Arbeit auszuführen, aber das Initialisieren spart uns Zeit und Codezeilen.

Dies ist die einzige Aufgabe zum Initialisieren. Sie können die Initialisierung 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. Weitere Einzelheiten hierzu finden Sie weiter unten.

Getters, Setter (attr_reader, attr_writer, attr_accessor)

Getters, attr_reader: Der gesamte Zweck eines Getters besteht darin, den Wert einer bestimmten Instanzvariablen zurückzugeben. Besuchen Sie den folgenden Beispielcode, um eine Aufschlüsselung zu diesem Thema zu erhalten.

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 "Puts example.item_name" und "example.quantity" geben den Wert für die Parameter zurück (oder "get"), die an das "example" übergeben wurden, und zeigen sie auf dem Bildschirm an.

Glücklicherweise gibt es in Ruby eine inhärente Methode, mit der wir diesen Code prägnanter 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 wir sechs Codezeilen sparen. Stellen Sie sich vor, Sie hätten 5 weitere Status, die der Item-Klasse zugeordnet werden können? Der Code würde schnell lang werden.

Setter, attr_writer: Was mich anfangs mit Setter-Methoden beschäftigt hat, ist, dass es in meinen Augen eine identische Funktion wie die Initialisierungsmethode zu haben schien. Im Folgenden erkläre ich den Unterschied anhand meines Verständnisses.

Wie bereits erwähnt, können Sie mit der Initialisierungsmethode die Werte für eine Instanz eines Objekts bei der Objekterstellung festlegen.

Was aber, wenn Sie die Werte später nach dem Erstellen der Instanz festlegen oder nach der Initialisierung ändern möchten? Dies wäre ein Szenario, in dem Sie eine Setter-Methode verwenden würden. DAS IST DER UNTERSCHIED. Sie müssen keinen bestimmten Status festlegen, wenn Sie anfänglich die attr_writer-Methode 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 drucken 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 erneut 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 und spart Ihnen eine weitere Codezeile.

Jbur43
quelle
10

Ich denke, ein Teil dessen, was neue Rubyisten / Programmierer (wie mich) verwirrt, ist:

"Warum kann ich der Instanz nicht einfach sagen, dass sie ein bestimmtes Attribut (z. B. einen Namen) hat, und diesem Attribut auf einen Schlag einen Wert geben?"

Ein bisschen allgemeiner, 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.

Also wenn wir dann:

baby = Person.new

... und versuche ihnen einen Namen zu geben ...

baby.name = "Ruth"

Wir erhalten eine Fehlermeldung, weil in Rubyland eine Person-Objektklasse nicht mit einem "Namen" assoziiert ist oder einen solchen haben kann ... noch nicht!

ABER wir können jede der angegebenen Methoden verwenden (siehe vorherige Antworten), um zu sagen: "Eine Instanz einer Person-Klasse ( baby) kann jetzt ein Attribut namens 'name' haben, daher haben wir nicht nur eine syntaktische Methode, um und zu erhalten diesen Namen setzen, aber es ist sinnvoll für uns, dies zu tun. "

Wiederum diese Frage aus einem etwas anderen und allgemeineren Blickwinkel zu beantworten, aber ich hoffe, dies hilft der nächsten Instanz der Klasse Person, die ihren Weg zu diesem Thread findet.

Ben
quelle
7

Einfach ausgedrückt definiert es einen Setter und 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

Damit

attr_accessor :v which means 
attr_reader :v; attr_writer :v 

sind äquivalent, um einen Setter und einen Getter für die Klasse zu definieren.

Marcus Thornton
quelle
5

Erstellt einfach attr-accessordie Methoden getterund setterfür die angegebenen Attribute

Veeru
quelle
5

Eine andere Möglichkeit, dies zu verstehen, besteht darin, herauszufinden, welchen Fehlercode durch das Entfernen beseitigt wird attr_accessor.

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 lösen einen Fehler aus:

$ bankie.owner     #undefined method `owner'... 
$ bankie.balance   #undefined method `balance'...

ownerund balancesind technisch gesehen keine Methode , sondern ein Attribut. Bankaccount - Klasse nicht haben def ownerund def balance. Wenn dies der Fall ist, können Sie die beiden folgenden Befehle verwenden. Aber diese beiden Methoden sind nicht da. Sie können jedoch auf Attribute zugreifen , als würden Sie über !! auf eine Methode zugreifen. Daher das Wort . Attribut. Accessor. Es greift auf Attribute zu, als würden Sie auf eine Methode zugreifen.attr_accessorattr_accessor

Durch Hinzufügen attr_accessor :balance, :ownerkönnen Sie lesen und schreiben balanceund owner"Methode". Jetzt können Sie die letzten beiden Methoden verwenden.

$ bankie.balance
$ bankie.owner
Iggy
quelle
2

Definiert ein benanntes Attribut für dieses Modul, wobei der Name symbol.id2name lautet, und erstellt eine Instanzvariable (@name) und eine entsprechende Zugriffsmethode zum 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=]
Praveen_Shukla
quelle
1

Um ein Attribut Accessor alias attr_accessor zusammenzufassen, stehen Ihnen zwei kostenlose Methoden zur Verfügung.

Wie in Java werden sie Getter und Setter genannt.

Viele Antworten haben gute Beispiele gezeigt, deshalb werde ich mich nur kurz fassen.

#the_attribute

und

# the_attribute =

In den alten Ruby-Dokumenten bedeutet ein Hash-Tag # eine Methode. Es könnte auch ein Klassennamenpräfix enthalten ... MyClass # my_method

Douglas G. Allen
quelle
1

Ich bin neu in Ruby und musste mich nur mit dem Verständnis der folgenden Verrücktheit befassen. Könnte in Zukunft jemand anderem helfen. Am Ende ist es wie oben erwähnt, wo 2 Funktionen (def myvar, def myvar =) implizit für den Zugriff auf @myvar abgerufen werden, aber diese Methoden können 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
Adverbly
quelle
0

Attribute und Zugriffsmethoden

Attribute sind Klassenkomponenten, auf die von außerhalb des Objekts zugegriffen werden kann. Sie sind in vielen anderen Programmiersprachen als Eigenschaften bekannt. Auf ihre Werte kann mithilfe der "Punktnotation" wie in object_name.attribute_name zugegriffen werden. 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 (ein Objekt) der Car-Klasse. Wir haben erfolglos versucht, den Wert der Instanzvariablen der Räder von außerhalb des Objekts zu lesen. Was passiert ist, ist, dass Ruby versucht hat, eine Methode namens ribs innerhalb des c-Objekts aufzurufen, aber keine solche Methode wurde definiert. Kurz gesagt, object_name.attribute_name versucht, eine Methode namens attribute_name innerhalb des Objekts aufzurufen. Um von außen auf den Wert der Radvariablen zuzugreifen, 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 die übliche Möglichkeit, von außerhalb des Objekts auf eine Instanzvariable zuzugreifen, darin, Zugriffsmethoden zu implementieren, die auch als Getter- und Setter-Methoden bezeichnet werden.

Im folgenden Beispiel haben wir der Car-Klasse Getter- und Setter-Methoden hinzugefügt, um von außerhalb des Objekts auf die Rädervariable zuzugreifen. Dies ist nicht die "Ruby-Methode", um Getter und Setter zu definieren. Es dient nur zur Veranschaulichung der Funktionsweise von Getter- und Setter-Methoden.

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 verwendet, um Getter- und Setter-Methoden in anderen Sprachen zu erstellen. Ruby bietet jedoch eine einfachere Möglichkeit, dies zu tun: drei integrierte Methoden namens attr_reader, attr_writer und attr_acessor. Die attr_reader-Methode macht eine Instanzvariable von außen lesbar, attr_writer macht sie beschreibbar und attr_acessor macht sie lesbar und beschreibbar.

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 Attribut "Räder" von außerhalb des Objekts lesbar und beschreibbar. Wenn wir anstelle von attr_accessor attr_reader verwenden würden, wäre dies schreibgeschützt. Wenn wir attr_writer verwenden würden, wäre es schreibgeschützt. Diese drei Methoden sind an sich keine Getter und Setter, aber wenn sie aufgerufen werden, erstellen sie Getter- und Setter-Methoden für uns. Dies sind Methoden, die dynamisch (programmgesteuert) andere Methoden generieren. Das nennt man Metaprogrammierung.

Das erste (längere) Beispiel, in dem Rubys integrierte Methoden 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 Instanzvariablen ein Wert zugewiesen wird.

Mit den integrierten Methoden instance_variable_get und instance_variable_set können Sie von außerhalb des Objekts auf Instanzvariablen zugreifen (diese lesen und schreiben). Dies ist jedoch selten zu rechtfertigen und in der Regel eine schlechte Idee, da die Umgehung der Kapselung dazu neigt, alle Arten von Chaos zu verursachen.

BrunoFacca
quelle
-2

Hmmm. Viele gute Antworten. Hier sind meine paar Cent drauf.

  • attr_accessorist eine einfache Methode, die uns beim Reinigen ( TROCKNEN ) der Wiederholungsmethodengetter and setter hilft .

  • Damit wir uns mehr auf das Schreiben von Geschäftslogik konzentrieren können und uns nicht um die Setter und Getter kümmern müssen.

Abibullah Rahamathulah
quelle
-3

Die Hauptfunktionalität von attr_accessor gegenüber den anderen ist die Möglichkeit, auf Daten aus anderen Dateien zuzugreifen.
Normalerweise haben Sie attr_reader oder attr_writer, aber die gute Nachricht ist, dass Sie mit Ruby diese beiden mit attr_accessor kombinieren können. Ich betrachte es als meine To-Go-Methode, weil es runder oder vielseitiger ist. Denken Sie auch daran, dass dies in Rails beseitigt ist, da es im Back-End für Sie erledigt wird. Mit anderen Worten: Sie sind besser dran, attr_acessor gegenüber den beiden anderen zu verwenden, da Sie sich keine Sorgen machen müssen, dass Sie zu spezifisch sind. Der Accessor deckt alles ab. Ich weiß, dass dies eher eine allgemeine Erklärung ist, aber es hat mir als Anfänger geholfen.

Hoffe das hat geholfen!

creativegeek
quelle