2011-11-03 2 views
5

Ran in un comportamento strano e chiedendosi se qualcun altro può confermare ciò che sto vedendo.Ruby attr_reader consente di modificare la variabile stringa se si utilizza <<

Supponiamo di creare una classe con una variabile membro e consentirne la lettura con attr_reader.

class TestClass 
    attr_reader :val 

    def initialize(value) 
    @val = value 
    end 
end 

Ora, quando faccio la seguente, sembra modificare il valore di @val, anche se ho concesso soltanto leggere i privilegi.

test = TestClass.new('hello') 
puts test.val 
test.val << ' world' 
puts test.val 

Ciò restituisce

hello 
hello world 

Questo è solo il risultato di alcuni test che ho fatto in IRB quindi non so se questo è sempre il caso

+0

"attr_reader" significa che non è possibile impostare il valore, vale a dire nessun metodo 'value =' è definito. Certamente non significa che non si può calalizzare un metodo sull'oggetto –

risposta

4

non siete veramente scrivendo l'attributo val. Stai leggendo e invocando un metodo su di esso (il metodo '< <').

Se si desidera una funzione di accesso che impedisca il tipo di modifica che si descrive, è possibile implementare un metodo che restituisce una copia di @val anziché utilizzare attr_reader.

2

Basta una piccola modifica del vostro esempio:

test = TestClass.new([]) 

Ora si dovrebbe ottenere (sostituire mette con p per ottenere la vista interna):

[] 
['hello'] 

E 'la stessa cosa. Tu leggi 'val, e ora puoi fare qualcosa con esso. Nel mio esempio, aggiungi qualcosa alla matrice, nel tuo esempio aggiungi qualcosa alla tua stringa.

L'accesso in lettura legge l'oggetto (che può essere modificato), l'accesso in scrittura modifica l'attributo (lo sostituisce).

Forse cerchi freeze:

class TestClass 
    attr_reader :val 

    def initialize(value) 
    @val = value 
    @val.freeze 
    end 
end 

test = TestClass.new('hello') 
puts test.val 
test.val << ' world' 
puts test.val 

Questo termina in:

__temp.rb:12:in `<main>': can't modify frozen string (RuntimeError) 
hello 
0

Anche se questo sembra inaspettato, questo è esattamente a destra. Lasciatemi spiegare.

I metodi macro di classe attr_reader e attr_writer definiscono metodi "getter" e "setter" per variabili di istanza.

Senza un metodo "getter", non si ha accesso alle variabili di istanza di un oggetto semplicemente perché non si è nel contesto di tale oggetto. Il metodo "setter" è essenzialmente questo:

def variable=(value) 
    @variable = value 
end 

Dal momento che le istanze variabile punta ad un oggetto mutabile con una serie di metodi di sé, se si "salire" e manipolarlo, è ovvio che queste modifiche saranno prendere. Non è necessario utilizzare il metodo setter sopra per chiamare variable.<<(value).

2

L'assegnazione è diversa dalla modifica e le variabili sono diverse dagli oggetti.

test.val = "hello world" 

sarebbe un caso di assegnazione alla variabile @valesempio (che non funziona), considerando che

test.val << " world" 

sarebbe un modifica del dell'oggetto cui di @val.

Why does the absence of the assignment operator permit me to modify a Ruby constant with no compiler warning? è una domanda simile, ma si parla di costanti piuttosto che di variabili di istanza.