2011-11-03 5 views
5

Se topa con un comportamiento extraño y se pregunta si alguien más puede confirmar lo que estoy viendo.Ruby attr_reader le permite a uno modificar la variable de cadena si usa <<

Supongamos que crea una clase con una variable miembro y permite que se lea con attr_reader.

class TestClass 
    attr_reader :val 

    def initialize(value) 
    @val = value 
    end 
end 

Ahora, cuando hago lo siguiente, parece modificar el valor de @val, a pesar de que sólo he concedido privilegios de lectura.

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

Esto devuelve

hello 
hello world 

Esto es sólo el resultado de algunas pruebas que hice en IRB así que no sé si esto es siempre el caso

+0

'attr_reader' significa que no puede establecer el valor, es decir, no se define ningún método' value = '. Ciertamente no significa que no se puede calcular un método en el objeto –

Respuesta

4

usted no está realmente escribiendo el atributo val. Lo está leyendo e invocando un método (el método '< <').

Si desea un descriptor de acceso que impida el tipo de modificación que describe, es posible que desee implementar un método que devuelva una copia de @val en lugar de usar attr_reader.

2

Sólo una pequeña modificación de su ejemplo:

test = TestClass.new([]) 

Ahora usted debe conseguir (sustituir pone con P para obtener la vista interna):

[] 
['hello'] 

Es lo mismo. Usted "lee" val, y ahora puede hacer algo con eso. En mi ejemplo, agregas algo a la matriz, en tu ejemplo agregas algo a tu cadena.

Read-access lee el objeto (que se puede modificar), write-access cambia el atributo (lo reemplaza).

Tal vez es lo que busca 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 

Esto termina en:

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

Si bien esto parece inesperada, esto es exactamente correcto. Dejame explicar.

Los métodos de macro de clase attr_reader y attr_writer definen los métodos "getter" y "setter" para las variables de instancia.

Sin un método "getter", no tiene acceso a las variables de instancia de un objeto simplemente porque no se encuentra en el contexto de ese objeto. El método "setter" es esencialmente la siguiente:

def variable=(value) 
    @variable = value 
end 

Desde la instancia variable apunta a un objeto mutable con un conjunto de sí mismo métodos, si se "obtiene" y manipularlo, es lógico pensar que esos cambios se tomar. No necesita usar el método setter anterior para llamar al variable.<<(value).

2

La asignación es diferente a la modificación, y las variables son diferentes a los objetos.

test.val = "hello world" 

sería un caso de asignación a la @valinstancia de variable (que no funcionaría), mientras que

test.val << " world" 

sería una modificación de la objeto se refiere por @val.

Why does the absence of the assignment operator permit me to modify a Ruby constant with no compiler warning? es una pregunta similar, pero hablando de constantes en lugar de variables de instancia.

Cuestiones relacionadas