Frage Was ist attr_accessor in Ruby?


Mir fällt es schwer zu verstehen attr_accessor in Rubin. Kann mir das jemand erklären?


862
2017-12-06 21:07


Ursprung


Antworten:


Nehmen wir an, 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 vergeben können. Das sind zwei verschiedene Methoden. Der ehemalige heißt Leser und letzteres wird genannt Schriftsteller. Wir haben den Schreiber 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 schreiben und lesen @name Lese- und Schreibmethoden verwenden. Abgesehen davon, dass dies so häufig geschieht, warum sollte man diese Methoden jedes Mal verschwenden? Wir können es einfacher machen.

class Person
  attr_reader :name
  attr_writer :name
end

Auch das kann sich wiederholen. Wenn Sie möchten, dass sowohl Leser als auch Autor Accessor verwenden!

class Person
  attr_accessor :name
end

person = Person.new
person.name = "Dennis"
person.name # => "Dennis"

Funktioniert auf die gleiche Weise! Und rate mal was: die Instanzvariable @name In unserem Person-Objekt wird genau so eingestellt, wie wenn wir es manuell gemacht haben, also können Sie es in anderen Methoden verwenden.

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 generieren Methoden für Sie, lesen Sie andere Antworten, Bücher, Ruby Docs.


2046
2017-12-06 22:11



attr_accessor ist nur eine Methode. (Der Link sollte mehr Einblick in die Funktionsweise geben. Schauen Sie sich die generierten Methodenpaare an und ein Tutorial soll Ihnen zeigen, wie Sie es verwenden können.)

Der Trick ist das class ist keine Definition in Ruby (es ist "nur eine Definition" in Sprachen wie C ++ und Java), aber es ist ein Ausdruck, der auswertet. Es ist während dieser Auswertung wenn der attr_accessor Methode wird aufgerufen, die wiederum die aktuelle Klasse ändert - erinnern Sie sich an den impliziten Empfänger: self.attr_accessor, woher self ist das "offene" Klassenobjekt an diesem Punkt.

Das Bedürfnis nach attr_accessor und Freunde, ist, gut:

  1. Wie Smalltalk erlaubt Ruby keinen Zugriff auf Instanzvariablen außerhalb von Methoden1 für dieses Objekt. Das heißt, auf Instanzvariablen kann nicht zugegriffen werden x.y Form wie es in Java oder Python üblich ist. In Ruby y wird immer als eine Nachricht zum Senden (oder "Methode zum Anrufen") genommen. Und so kam es dass der attr_* Methoden erstellen Wrapper, die die Instanz Proxy @variable Zugriff über dynamisch erstellte Methoden.

  2. Kesselplatte saugt

Hoffe das klärt einige der kleinen Details. Glückliche Kodierung.


1 Dies ist nicht streng zutreffend und es gibt einige "Techniken" um diese, aber es gibt keine Syntaxunterstützung für den Zugriff auf "öffentliche Instanzvariable".


114
2017-12-06 21:21



attr_accessor ist (wie @pst angegeben) nur eine Methode. Was es tut, ist mehr Methoden für Sie zu erstellen.

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

62
2017-12-06 21:29



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 anderes als ein Getter / Setter für ein Objekt


35
2017-12-06 21:28



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
2017-12-06 21:29



Im Grunde fälschen sie öffentlich zugängliche Datenattribute, die Ruby nicht hat.


16
2017-12-06 21:11



Ich habe mich auch diesem Problem gestellt und eine etwas längere Antwort auf diese Frage geschrieben. Es gibt schon einige gute Antworten darauf, aber wer nach mehr Klarheit sucht, der kann mit meiner Antwort helfen

Initialisierungsmethode

Mit Initialize können Sie bei der Erstellung der Instanz Daten für eine Instanz eines Objekts festlegen, anstatt sie bei jeder Erstellung einer neuen Instanz der Klasse in einer eigenen Zeile im Code festzulegen.

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 Initialisierungsmethode setzen wollten, könnten wir das so machen:

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 setzen wir den Namen, indem wir die Methode attr_accessor setter mit person.name aufrufen, anstatt die Werte bei der Initialisierung des Objekts zu setzen.

Beide "Methoden", diese Arbeit zu tun, aber initialisieren spart uns Zeit und Codezeilen.

Dies ist der einzige Job, der initialisiert wird. Sie können initialize nicht als Methode aufrufen. Um die Werte eines Instanzobjekts tatsächlich zu erhalten, müssen Sie Getter und Setter verwenden (attr_reader (get), attr_writer (set) und attr_accessor (beide)). Siehe unten für mehr Details zu diesen.

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. Im folgenden Beispielcode finden Sie eine Übersicht dazu.

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" werden den Wert für die Parameter, die an das "Beispiel" übergeben wurden, zurückgeben (oder "holen") und sie auf dem Bildschirm anzeigen.

Zum Glück gibt es in Ruby eine inhärente Methode, die es erlaubt, diesen Code prägnanter zu schreiben; die attr_reader-Methode. Siehe den folgenden Code;

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 genau so, nur dass wir sechs Zeilen Code sparen. Stellen Sie sich vor, Sie hätten der Item-Klasse 5 weitere Zustände zuweisen können? Der Code würde schnell lang werden.

Setter, attr_writer: Was mich anfangs mit Setter-Methoden kreuzte, ist, dass es in meinen Augen eine identische Funktion wie die Initialisierungsmethode zu erfüllen 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 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 einen bestimmten Status nicht festlegen, wenn Sie die Methode attr_writer verwenden.

Der folgende Code ist ein Beispiel für die Verwendung einer Setter-Methode zum Deklarieren des Werts item_name für diese Instanz der Item-Klasse. Beachten Sie, dass wir weiterhin die Getter-Methode attr_reader verwenden, damit wir die Werte abrufen und auf den 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 den Einsatz von attr_writer, um unseren Code noch einmal zu verkürzen und uns 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, in dem wir initialize verwenden, um den Objektwert von item_name beim Erstellen 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 speichert eine weitere Codezeile.


12
2017-09-16 01:03



Ich denke ein Teil von dem, was neue Rubyists / Programmierer verwirrt (wie ich) ist:

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

Etwas verallgemeinert, aber so hat es für mich geklickt:

Gegeben:

class Person
end

Wir haben keine Person definiert als etwas, das einen Namen haben kann oder irgendwelche anderen Attribute für diese Angelegenheit.

Also wenn wir dann:

baby = Person.new

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

baby.name = "Ruth"

Wir bekommen ein Error denn in Rubyland ist eine Personenklasse eines Objekts nicht etwas, das mit einem "Namen" verbunden ist oder in der Lage ist, einen "Namen" zu haben ... noch nicht!

ABER wir können eine der angegebenen Methoden verwenden (siehe vorherige Antworten), um zu sagen: "Eine Instanz einer Personenklasse (baby) kann jetzt Da wir ein Attribut namens 'name' haben, haben wir nicht nur einen syntaktischen Weg, diesen Namen zu bekommen und zu setzen, aber es ist auch sinnvoll, dies zu tun. "

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


10
2017-07-10 15:31



Wenn Sie mit dem OOP-Konzept vertraut sind, müssen Sie sich mit der Getter- und Setter-Methode vertraut machen. 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"

Setzer-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"

10
2018-02-08 07:22