Sto facendo fatica a capire attr_accessor
in Ruby .
Qualcuno può spiegarmelo?
git
non ha nulla a che fare con attr_accessor
. Git è un software di controllo della versione, mentre attr_accessor
è un metodo in Ruby .
Sto facendo fatica a capire attr_accessor
in Ruby .
Qualcuno può spiegarmelo?
git
non ha nulla a che fare con attr_accessor
. Git è un software di controllo della versione, mentre attr_accessor
è un metodo in Ruby .
Risposte:
Diciamo che hai una lezione Person
.
class Person
end
person = Person.new
person.name # => no method error
Ovviamente non abbiamo mai definito il metodo name
. Facciamolo.
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
Ah, possiamo leggere il nome, ma ciò non significa che possiamo assegnare il nome. Questi sono due metodi diversi. Il primo si chiama lettore e il secondo si chiama scrittore . Non abbiamo ancora creato lo scrittore, quindi facciamolo.
class Person
def name
@name
end
def name=(str)
@name = str
end
end
person = Person.new
person.name = 'Dennis'
person.name # => "Dennis"
Eccezionale. Ora possiamo scrivere e leggere la variabile di istanza @name
usando i metodi reader e writer. Tranne, questo viene fatto così frequentemente, perché perdere tempo a scrivere questi metodi ogni volta? Possiamo farlo più facilmente.
class Person
attr_reader :name
attr_writer :name
end
Anche questo può diventare ripetitivo. Quando vuoi sia il lettore che lo scrittore, usa Accessor!
class Person
attr_accessor :name
end
person = Person.new
person.name = "Dennis"
person.name # => "Dennis"
Funziona allo stesso modo! E indovina un po ': la variabile di istanza @name
nel nostro oggetto persona verrà impostata proprio come quando l'abbiamo fatta manualmente, quindi puoi usarla in altri metodi.
class Person
attr_accessor :name
def greeting
"Hello #{@name}"
end
end
person = Person.new
person.name = "Dennis"
person.greeting # => "Hello Dennis"
Questo è tutto. Per capire come attr_reader
, attr_writer
e attr_accessor
metodi effettivamente generare metodi per te, leggi altre risposte, libri, documenti rubini.
attr_accessor
è un metodo chiamato sulla classe corrente ed :name
è un parametro che passi a quel metodo. Non è una sintassi speciale, è una semplice chiamata di metodo. Se dovessi dargli una @name
variabile, non avrebbe senso, perché @name conterrebbe nil
. Quindi sarebbe come scrivere attr_accessor nil
. Non le stai passando una variabile che deve creare, stai passando il nome che vuoi che venga chiamata.
name
e variabile @name
non sono la stessa cosa. Non confonderli. Hai una variabile di istanza @name
nella tua classe e definisci attr_reader :name
di poterla leggere dall'esterno. Senza attr_reader
non esiste un modo semplice per accedere @name
al di fuori della tua classe.
attr_accessor è solo un metodo . (Il link dovrebbe fornire maggiori informazioni su come funziona: guarda le coppie di metodi generati e un tutorial dovrebbe mostrarti come usarlo.)
Il trucco è che nonclass
è una definizione in Ruby (è "solo una definizione" in linguaggi come C ++ e Java), ma è un'espressione che valuta . È durante questa valutazione attr_accessor
che viene invocato il metodo che a sua volta modifica la classe corrente - ricordare il ricevitore implicito:, self.attr_accessor
doveself
trova l'oggetto classe "aperto" a questo punto.
La necessità di attr_accessor
e amici, è, beh:
Ruby, come Smalltalk, non consente l'accesso alle variabili di istanza al di fuori dei metodi 1 per quell'oggetto. In altre x.y
parole, non è possibile accedere alle variabili di istanza nel modulo come è comune dire, Java o Python. In Ruby y
viene sempre considerato un messaggio da inviare (o "metodo da chiamare"). Pertanto i attr_*
metodi creano wrapper che proxy l' @variable
accesso all'istanza tramite metodi creati dinamicamente.
La caldaia fa schifo
Spero che questo chiarisca alcuni dei piccoli dettagli. Buona codifica.
1 Questo non è strettamente vero e ci sono alcune "tecniche" attorno a questo , ma non esiste un supporto di sintassi per l'accesso "variabile di istanza pubblica".
attr_accessor
è (come affermato da @pst) solo un metodo. Quello che fa è creare più metodi per te.
Quindi questo codice qui:
class Foo
attr_accessor :bar
end
è equivalente a questo codice:
class Foo
def bar
@bar
end
def bar=( new_value )
@bar = new_value
end
end
Puoi scrivere questo tipo di metodo tu stesso in Ruby:
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
e finalmente trovato qui! Sebbene abbia risolto il mio problema, ma sono curioso di sapere dove (libro / documento ufficiale) posso trovare un esempio di implementazione come questo?
attr_accessor
è molto semplice:
attr_accessor :foo
è una scorciatoia per:
def foo=(val)
@foo = val
end
def foo
@foo
end
non è altro che un getter / setter per un oggetto
Fondamentalmente falsificano attributi di dati accessibili al pubblico, che Ruby non ha.
È solo un metodo che definisce i metodi getter e setter per le variabili di istanza. Un'implementazione di esempio sarebbe:
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
La maggior parte delle risposte di cui sopra utilizza il codice. Questa spiegazione tenta di rispondere senza usare alcuna, tramite un'analogia / storia:
Le parti esterne non possono accedere ai segreti interni della CIA
Immaginiamo un posto davvero segreto: la CIA. Nessuno sa cosa sta succedendo nella CIA a parte le persone all'interno della CIA. In altre parole, le persone esterne non possono accedere ad alcuna informazione nella CIA. Ma poiché non è una buona cosa avere un'organizzazione completamente segreta, alcune informazioni sono rese disponibili al mondo esterno - solo cose che la CIA desidera naturalmente che tutti sappiano: ad esempio il direttore della CIA, quanto questo dipartimento sia rispettoso dell'ambiente a tutti gli altri dipartimenti governativi ecc. Altre informazioni: ad esempio chi sono i suoi agenti segreti in Iraq o in Afghanistan - questo tipo di cose rimarrà probabilmente un segreto per i prossimi 150 anni.
Se sei al di fuori della CIA puoi accedere solo alle informazioni che ha reso disponibili al pubblico. O per usare il linguaggio CIA puoi accedere solo alle informazioni "cancellate".
Le informazioni che la CIA vuole mettere a disposizione del pubblico esterno alla CIA sono chiamate: attributi.
Il significato degli attributi di lettura e scrittura:
Nel caso della CIA, la maggior parte degli attributi sono "sola lettura". Ciò significa che se sei una parte esterna alla CIA, puoi chiedere: "chi è il direttore della CIA?" e otterrai una risposta diretta. Ma ciò che non è possibile fare con gli attributi "sola lettura" è apportare modifiche alla CIA. ad esempio, non è possibile effettuare una telefonata e decidere all'improvviso che si desidera che Kim Kardashian sia il direttore o che si desideri che Paris Hilton sia il comandante in capo.
Se gli attributi ti davano accesso "in scrittura", allora puoi apportare modifiche se lo desideri, anche se eri all'esterno. Altrimenti, l'unica cosa che puoi fare è leggere.
In altre parole, gli accessor consentono di effettuare richieste o di apportare modifiche a organizzazioni che altrimenti non consentono l'accesso a persone esterne, a seconda che gli accessor siano accessi di lettura o scrittura.
Gli oggetti all'interno di una classe possono facilmente accedere l'un l'altro
La stessa cosa con le classi e la tua capacità di accedere a variabili, proprietà e metodi al loro interno. HTH! Per qualsiasi domanda, si prega di chiedere e spero di poter chiarire.
Se hai familiarità con il concetto di OOP, devi conoscere il metodo getter e setter. attr_accessor fa lo stesso in Ruby.
Getter e Setter in modo generale
class Person
def name
@name
end
def name=(str)
@name = str
end
end
person = Person.new
person.name = 'Eshaan'
person.name # => "Eshaan"
Metodo Setter
def name=(val)
@name = val
end
Metodo Getter
def name
@name
end
Metodo Getter e Setter in Ruby
class Person
attr_accessor :name
end
person = Person.new
person.name = "Eshaan"
person.name # => "Eshaan"
Ho anche affrontato questo problema e ho scritto una risposta piuttosto lunga a questa domanda. Ci sono già ottime risposte su questo, ma chiunque cerchi ulteriori chiarimenti, spero che la mia risposta possa essere d'aiuto
Metodo di inizializzazione
Initialize consente di impostare i dati su un'istanza di un oggetto al momento della creazione dell'istanza anziché doverli impostare su una riga separata nel codice ogni volta che si crea una nuova istanza della classe.
class Person
def initialize(name)
@name = name
end
def greeting
"Hello #{@name}"
end
end
person = Person.new("Denis")
puts person.greeting
Nel codice sopra stiamo impostando il nome "Denis" usando il metodo di inizializzazione passando Dennis attraverso il parametro in Initialize. Se volessimo impostare il nome senza il metodo di inizializzazione, potremmo farlo in questo modo:
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
Nel codice sopra, impostiamo il nome chiamando il metodo setter attr_accessor usando person.name, anziché impostare i valori all'inizializzazione dell'oggetto.
Entrambi i "metodi" per fare questo lavoro, ma l'inizializzazione ci fa risparmiare tempo e righe di codice.
Questo è l'unico lavoro di inizializzazione. Non è possibile chiamare l'inizializzazione come metodo. Per ottenere effettivamente i valori di un oggetto istanza è necessario utilizzare getter e setter (attr_reader (get), attr_writer (set) e attr_accessor (entrambi)). Vedi sotto per maggiori dettagli su quelli.
Getters, Setters (attr_reader, attr_writer, attr_accessor)
Getters, attr_reader: l'intero scopo di un getter è di restituire il valore di una particolare variabile di istanza. Visita il seguente codice di esempio per una suddivisione su questo.
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
Nel codice sopra si chiamano i metodi "nome_articolo" e "quantità" sull'istanza dell'articolo "esempio". "Put example.item_name" e "example.quantity" restituiranno (o "get") il valore per i parametri che sono stati passati nell '"esempio" e li visualizzeranno sullo schermo.
Fortunatamente in Ruby esiste un metodo intrinseco che ci consente di scrivere questo codice in modo più succinto; il metodo attr_reader. Vedi il codice qui sotto;
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
Questa sintassi funziona esattamente allo stesso modo, solo che ci salva sei righe di codice. Immagina se avessi altri 5 stati attribuibili alla classe Item? Il codice si allungherebbe rapidamente.
Setters, attr_writer: Ciò che inizialmente mi ha incrociato con i metodi setter è che ai miei occhi sembrava svolgere una funzione identica al metodo di inizializzazione. Di seguito spiego la differenza in base alla mia comprensione;
Come affermato in precedenza, il metodo di inizializzazione consente di impostare i valori per un'istanza di un oggetto al momento della creazione dell'oggetto.
E se volessi impostare i valori in un secondo momento, dopo la creazione dell'istanza, o modificarli dopo che sono stati inizializzati? Questo sarebbe uno scenario in cui useresti un metodo setter. QUESTA È LA DIFFERENZA. Non è necessario "impostare" uno stato particolare quando si utilizza inizialmente il metodo attr_writer.
Il codice seguente è un esempio dell'uso di un metodo setter per dichiarare il valore item_name per questa istanza della classe Item. Si noti che continuiamo a utilizzare il metodo getter attr_reader in modo da poter ottenere i valori e stamparli sullo schermo, nel caso in cui si desideri testare il codice da soli.
class Item
attr_reader :item_name
def item_name=(str)
@item_name = (str)
end
end
Il codice seguente è un esempio dell'utilizzo di attr_writer per abbreviare ancora una volta il nostro codice e farci risparmiare tempo.
class Item
attr_reader :item_name
attr_writer :item_name
end
item = Item.new
puts item.item_name = "TV"
Il codice seguente è una reiterazione dell'esempio di inizializzazione sopra di dove stiamo usando inizializzare per impostare il valore degli oggetti di nome_elemento al momento della creazione.
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: esegue le funzioni di attr_reader e attr_writer, risparmiando un'altra riga di codice.
Penso che parte di ciò che confonde i nuovi rubyisti / programmatori (come me) sia:
"Perché non posso semplicemente dire all'istanza che ha un dato attributo (ad esempio, nome) e dare a quell'attributo un valore tutto in un colpo solo?"
Un po 'più generalizzato, ma è così che mi ha fatto clic:
Dato:
class Person
end
Non abbiamo definito Person come qualcosa che può avere un nome o altri attributi per quella materia.
Quindi se poi:
baby = Person.new
... e prova a dare loro un nome ...
baby.name = "Ruth"
Abbiamo un errore perché, in Rubyland, una classe di oggetti Person non è qualcosa che è associato o in grado di avere un "nome" ... ancora!
MA possiamo usare uno dei metodi indicati (vedi le risposte precedenti) come modo per dire "Un'istanza di una classe Person (baby
) ora può avere un attributo chiamato 'name', quindi non abbiamo solo un modo sintattico di ottenere e impostando quel nome, ma per noi ha senso farlo ".
Ancora una volta, rispondere a questa domanda da un punto di vista leggermente diverso e più generale, ma spero che questo aiuti la prossima istanza della persona di classe che trova la sua strada in questo thread.
In poche parole definirà un setter e getter per la classe.
Nota che
attr_reader :v is equivalant to
def v
@v
end
attr_writer :v is equivalant to
def v=(value)
@v=value
end
Così
attr_accessor :v which means
attr_reader :v; attr_writer :v
sono equivalenti per definire un setter e getter per la classe.
Un altro modo per capirlo è capire quale codice di errore elimina avendo attr_accessor
.
Esempio:
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
Sono disponibili i seguenti metodi:
$ bankie = BankAccout.new("Iggy")
$ bankie
$ bankie.deposit(100)
$ bankie.withdraw(5)
I seguenti metodi generano errore:
$ bankie.owner #undefined method `owner'...
$ bankie.balance #undefined method `balance'...
owner
e balance
non sono, tecnicamente, un metodo , ma un attributo. La classe BankAccount non ha def owner
e def balance
. In tal caso, è possibile utilizzare i due comandi seguenti. Ma quei due metodi non ci sono. Tuttavia, puoi accedere agli attributi come se dovessi accedere a un metodo tramite attr_accessor
!! Da qui la parolaattr_accessor
. Attributo. Accessor. Accede ad attributi come se dovessi accedere a un metodo.
L'aggiunta attr_accessor :balance, :owner
consente di leggere e scrivere balance
e owner
"metodo". Ora puoi usare gli ultimi 2 metodi.
$ bankie.balance
$ bankie.owner
Definisce un attributo denominato per questo modulo, dove il nome è symbol.id2name, creando una variabile di istanza (@name) e un metodo di accesso corrispondente per leggerlo. Crea anche un metodo chiamato name = per impostare l'attributo.
module Mod
attr_accessor(:one, :two)
end
Mod.instance_methods.sort #=> [:one, :one=, :two, :two=]
Per riassumere un attributo accessor aka attr_accessor ti offre due metodi gratuiti.
Come in Java vengono chiamati getter e setter.
Molte risposte hanno mostrato buoni esempi, quindi sarò solo breve.
#the_attribute
e
# The_attribute =
Nei vecchi documenti ruby un tag hash # significa un metodo. Potrebbe anche includere un prefisso del nome classe ... MyClass # my_method
Sono nuovo di Ruby e ho dovuto fare i conti con la comprensione della seguente stranezza. Potrebbe aiutare qualcun altro in futuro. Alla fine è come accennato in precedenza, dove 2 funzioni (def myvar, def myvar =) ottengono entrambe implicitamente per accedere a @myvar, ma questi metodi possono essere ignorati dalle dichiarazioni locali.
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
Gli attributi sono componenti di classe a cui è possibile accedere dall'esterno dell'oggetto. Sono conosciuti come proprietà in molti altri linguaggi di programmazione. I loro valori sono accessibili usando la "notazione punto", come in nome_oggetto.nome_attributo. A differenza di Python e di alcune altre lingue, Ruby non consente l'accesso alle variabili di istanza direttamente dall'esterno dell'oggetto.
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>
Nell'esempio precedente, c è un'istanza (oggetto) della classe Car. Abbiamo tentato senza successo di leggere il valore della variabile di istanza wheels dall'esterno dell'oggetto. Quello che è successo è che Ruby ha tentato di chiamare un metodo chiamato wheels all'interno dell'oggetto c, ma non è stato definito tale metodo. In breve, object_name.attribute_name tenta di chiamare un metodo denominato nome_attributo all'interno dell'oggetto. Per accedere al valore della variabile wheels dall'esterno, è necessario implementare un metodo di istanza con quel nome, che restituirà il valore di quella variabile quando viene chiamato. Si chiama metodo di accesso. Nel contesto generale di programmazione, il solito modo per accedere a una variabile di istanza dall'esterno dell'oggetto è implementare metodi di accesso, noti anche come metodi getter e setter.
Nel seguente esempio, abbiamo aggiunto i metodi getter e setter alla classe Car per accedere alla variabile ruote dall'esterno dell'oggetto. Questa non è la "via vermiglia" per definire getter e setter; serve solo per illustrare cosa fanno i metodi getter e setter.
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
L'esempio sopra funziona e un codice simile viene comunemente usato per creare metodi getter e setter in altre lingue. Tuttavia, Ruby fornisce un modo più semplice per farlo: tre metodi integrati chiamati attr_reader, attr_writer e attr_acessor. Il metodo attr_reader rende leggibile una variabile di istanza dall'esterno, attr_writer la rende scrivibile e attr_acessor la rende leggibile e scrivibile.
L'esempio sopra può essere riscritto in questo modo.
class Car
attr_accessor :wheels
end
f = Car.new
f.wheels = 4
f.wheels # Output: => 4
Nell'esempio sopra, l'attributo wheels sarà leggibile e scrivibile dall'esterno dell'oggetto. Se invece di attr_accessor, utilizzassimo attr_reader, sarebbe di sola lettura. Se usassimo attr_writer, sarebbe di sola scrittura. Questi tre metodi non sono getter e setter in sé, ma, quando chiamati, creano metodi getter e setter per noi. Sono metodi che generano dinamicamente (programmaticamente) altri metodi; si chiama metaprogrammazione.
Il primo (più lungo) esempio, che non utilizza i metodi integrati di Ruby, dovrebbe essere usato solo quando è richiesto codice aggiuntivo nei metodi getter e setter. Ad esempio, potrebbe essere necessario che un metodo setter convalidi i dati o esegua alcuni calcoli prima di assegnare un valore a una variabile di istanza.
È possibile accedere (leggere e scrivere) alle variabili di istanza dall'esterno dell'oggetto, usando i metodi integrati instance_variable_get e instance_variable_set. Tuttavia, questo è raramente giustificabile e di solito una cattiva idea, poiché bypassare l'incapsulamento tende a provocare ogni sorta di caos.
Hmmm. Molte buone risposte. Ecco i miei pochi centesimi.
attr_accessor
è un metodo semplice che ci aiuta a ripulire ( DRY-ing ) i metodi ripetutigetter and setter
.
In modo che possiamo concentrarci maggiormente sulla scrittura della logica aziendale e non preoccuparci dei setter e dei getter.
La principale funzionalità di attr_accessor rispetto agli altri è la capacità di accedere ai dati da altri file.
Quindi di solito avresti attr_reader o attr_writer ma la buona notizia è che Ruby ti consente di combinare questi due insieme con attr_accessor. Lo considero come il mio metodo di andare perché è più ben arrotondato o versatile. Inoltre, tieni presente che in Rails, questo viene eliminato perché lo fa per te nel back-end. Quindi, in altre parole: è meglio usare attr_acessor rispetto agli altri due perché non devi preoccuparti di essere specifico, l'accessor copre tutto. So che questa è una spiegazione più generale, ma mi ha aiutato come principiante.
Spero che questo abbia aiutato!