¿Por qué utilizar attr_accessor, attr_reader y attr_writer de Ruby?

Resuelto Saturn asked hace 13 años • 5 respuestas

Ruby tiene esta manera práctica y conveniente de compartir variables de instancia usando claves como

attr_accessor :var
attr_reader :var
attr_writer :var

¿Por qué elegiría attr_readero attr_writersi simplemente podría utilizar attr_accessor? ¿Existe algo parecido al rendimiento (que dudo)? Supongo que hay una razón, de lo contrario no habrían hecho esas llaves.

Saturn avatar Feb 19 '11 04:02 Saturn
Aceptado

Puede utilizar los diferentes descriptores de acceso para comunicar su intención a alguien que lea su código y facilitar la escritura de clases que funcionarán correctamente sin importar cómo se llame su API pública.

class Person
  attr_accessor :age
  ...
end

Aquí puedo ver que puedo leer y escribir la edad.

class Person
  attr_reader :age
  ...
end

Aquí puedo ver que solo puedo leer la edad. Imagine que lo establece el constructor de esta clase y luego permanece constante. Si hubiera un mutador (escritor) para la edad y la clase se escribiera asumiendo que la edad, una vez establecida, no cambia, entonces podría producirse un error si el código llama a ese mutador.

Pero ¿qué está pasando detrás de escena?

Si tú escribes:

attr_writer :age

Eso se traduce en:

def age=(value)
  @age = value
end

Si tú escribes:

attr_reader :age

Eso se traduce en:

def age
  @age
end

Si tú escribes:

attr_accessor :age

Eso se traduce en:

def age=(value)
  @age = value
end

def age
  @age
end

Sabiendo eso, he aquí otra forma de pensarlo: si no tuviera los ayudantes attr_... y tuviera que escribir los descriptores de acceso usted mismo, ¿escribiría más descriptores de acceso de los que su clase necesita? Por ejemplo, si solo fuera necesario leer la edad, ¿escribiría también un método que permitiera escribirla?

Wayne Conrad avatar Feb 18 '2011 21:02 Wayne Conrad

Todas las respuestas anteriores son correctas; attr_readery attr_writerson más convenientes de escribir que escribir manualmente los métodos para los que son abreviaturas. Aparte de eso, ofrecen un rendimiento mucho mejor que escribir usted mismo la definición del método. Para obtener más información, consulte la diapositiva 152 en adelante de esta charla ( PDF ) de Aaron Patterson.

hawx avatar Apr 27 '2011 15:04 hawx

Es importante comprender que los descriptores de acceso restringen el acceso a las variables, pero no a su contenido. En Ruby, como en otros lenguajes OO, cada variable es un puntero a una instancia. Entonces, si tiene un atributo para un Hash, por ejemplo, y lo configura como "solo lectura", siempre podrá cambiar su contenido, pero no el contenido del puntero. Mira este:

> class A
>   attr_reader :a
>   def initialize
>     @a = {a:1, b:2}
>   end
> end
=> :initialize
> a = A.new
=> #<A:0x007ffc5a10fe88 @a={:a=>1, :b=>2}>
> a.a
=> {:a=>1, :b=>2}
> a.a.delete(:b)
=> 2
> a.a
=> {:a=>1}
> a.a = {}
NoMethodError: undefined method `a=' for #<A:0x007ffc5a10fe88 @a={:a=>1}>
        from (irb):34
        from /usr/local/bin/irb:11:in `<main>'

Como puede ver, es posible eliminar un par clave/valor del Hash @a, como agregar nuevas claves, cambiar valores, etc. Pero no puede apuntar a un objeto nuevo porque es una variable de instancia de solo lectura.

Korsmakolnikov avatar Jul 02 '2015 16:07 Korsmakolnikov