2012-10-16 11 views
23

I Ho appena iniziato a studiare Ruby e non vedo la differenza tra uno @instace_variable e un attributo dichiarato utilizzando attr_accessor.Differenza tra @istanza_variabile e attr_accessor

Qual è la differenza tra i due seguenti classi:

class MyClass 
    @variable1 
end 

e

class MyClass 
    attr_accessor :variable1 
end 

ho cercato sacco di tutorial on-line e tutti usano la notazione diversa, Ha a che fare qualcosa con il rubino versione? Ho cercato anche alcuni fili vecchi in StackOverflow

What is attr_accessor in Ruby?
What's the Difference Between These Two Ruby Class Initialization Definitions?

Ma ancora non sono in grado di capire qual è il modo migliore per utilizzare.

+3

'attr_accessor' creerà una variabile di istanza, i metodi _plus_ per leggere e scrivere la variabile di istanza. –

+4

In realtà, @AlexWayne, 'attr_accessor' dichiara solo i metodi. Le variabili di istanza non devono essere dichiarate; sorgono quando si tenta di accedervi (e il loro valore è 'nil' se quel primo accesso è una lettura anziché una scrittura). –

risposta

45

Una variabile di istanza non è visibile all'esterno dell'oggetto in cui si trova; ma quando crei un attr_accessor, crea una variabile di istanza e la rende visibile (e modificabile) anche all'esterno dell'oggetto.

Esempio con variabile di istanza (non attr_accessor)

class MyClass 
    def initialize 
    @greeting = "hello" 
    end 
end 

m = MyClass.new 
m.greeting #results in the following error: 
    #NoMethodError: undefined method `greeting' for #<MyClass:0x007f9e5109c058 @greeting="hello"> 

Esempio con attr_accessor:

class MyClass 
    attr_accessor :greeting 

    def initialize 
    @greeting = "hello" 
    end 
end 

m2 = MyClass.new 
m2.greeting = "bonjour" # <-- set the @greeting variable from outside the object 
m2.greeting #=> "bonjour" <-- didn't blow up as attr_accessor makes the variable accessible from outside the object 

speranza che rende chiaro.

+3

effettivamente sono da sfondo java e in java una variabile di istanza può essere resa visibile all'esterno usando i modificatori di accesso (pubblico, protetto), ecco perché non ero in grado di capire perché le variabili di istanza in ruby ​​non sono accessibili dall'esterno. Grazie per aver spiegato, evviva !!! –

+1

m2.greeting alla fine si trasforma in "ciao" – dtc

+0

Nat - @greeting = "ciao" dovrebbe essere cambiato in greeting = "ciao" perché come hai detto, attr_accessor crea già la variabile di istanza e le funzioni accessorie. Non è necessario utilizzare il simbolo @. –

7

attr_accesor fornisce metodi per leggere e scrivere le variabili di istanza. Le variabili di istanza sono state progettate per essere nascoste al di fuori del mondo, quindi per comunicare con loro dovremmo avere attr _ibute metodi di accesso.

25

Le variabili di istanza non sono visibili al di fuori della classe.

class MyClass 
    def initialize 
    @message = "Hello" 
    end 
end 

msg = MyClass.new 
@message 
#==> nil # This @message belongs to the global object, not msg 
msg.message 
#==> NoMethodError: undefined method `message' 
[email protected] 
#==> SyntaxError: syntax error, unexpected tIVAR 

Ora, si può sempre fare questo:

msg.instance_eval { @message } 

Ma questo è scomodo e cheatish. Giocare attorno alla classe di qualcun altro può essere educativo, ma il codice del tuo cliente non dovrebbe farlo se vuoi ottenere risultati affidabili. Il rovescio della medaglia, se vuoi che i client siano in grado di vedere quei valori, non farli usare instance_eval; invece, definire un metodo che fa il trucco:

class MyClass 
    def message 
    return @message 
    end 
end 
msg.message 
# ==> "Hello" 

Perché così spesso vuole fare questo, Ruby fornisce un collegamento per rendere più facile. Il seguente codice ha esattamente lo stesso risultato del codice sopra riportato:

class MyClass 
    attr_reader :message 
end 

Questo non è un nuovo tipo di variabile; è solo un modo stenografico per definire il metodo. Puoi guardare msg.methods e vedere che ora ha un metodo message.

Ora, che cosa succede se si desidera consentire agli estranei di non solo visualizzare il valore di una variabile di istanza, ma anche di modificarlo? Per questo, è necessario definire un metodo diverso per l'assegnazione, con un = nel nome:

class MyClass 
    def message=(new_value) 
    @message = new_value 
    end 
end 
msg.message = "Good-bye" 
msg.message 
# ==> "Good-bye" 

Nota che gli operatori di assegnazione sono semi-magica qui; anche se c'è uno spazio tra e =, Ruby sa ancora chiamare il metodo message=. Gli operatori di combinazione come += e così via attiveranno anche le chiamate al metodo.

Ancora una volta, questo è un disegno comune, in modo Rubino offre una scorciatoia per esso, anche:

class MyClass 
    attr_writer :message 
end 

Ora, se si utilizza attr_writer di per sé, si ottiene un attributo che può essere modificato, ma non si vede . Ci sono alcuni casi di utilizzo dispari in cui è quello che vuoi, ma il più delle volte, se hai intenzione di permettere agli estranei di modificare la variabile, vuoi che siano in grado di leggerla anche tu. Invece di dover dichiarare sia un attr_reader ed un attr_writer, è possibile dichiarare entrambi contemporaneamente in questo modo:

class MyClass 
    attr_accessor :message 
end 

Ancora una volta, questo è solo una scorciatoia per la definizione di metodi che consentono di ottenere alla variabile di istanza al di fuori della classe.

+4

questa è una risposta molto migliore e dettagliata che risponde chiaramente alla domanda per le persone che arrivano da altre lingue - grazie! – manroe

1

Poiché attr_accessor definisce i metodi, è possibile chiamarli dall'esterno della classe. A @variable è accessibile solo dall'interno della classe.