Pregunta ¿Qué es attr_accessor en Ruby?


Estoy teniendo dificultades para entender attr_accessor en Ruby. ¿Alguien me puede explicar esto?


862
2017-12-06 21:07


origen


Respuestas:


Digamos que tienes una clase Person.

class Person
end

person = Person.new
person.name # => no method error

Obviamente, nunca hemos definido el método name. Vamos a hacer eso.

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

Ajá, podemos leer el nombre, pero eso no significa que podamos asignar el nombre. Esos son dos métodos diferentes. El primero se llama lector y último se llama escritor. Aún no creamos el escritor, así que hagámoslo.

class Person
  def name
    @name
  end

  def name=(str)
    @name = str
  end
end

person = Person.new
person.name = 'Dennis'
person.name # => "Dennis"

Increíble. Ahora podemos escribir y leer variable de instancia @name usando métodos de lector y escritor. Excepto que esto se hace con tanta frecuencia, ¿por qué perder el tiempo escribiendo estos métodos todo el tiempo? Podemos hacerlo más fácil.

class Person
  attr_reader :name
  attr_writer :name
end

Incluso esto puede volverse repetitivo. ¡Cuando desee tanto el lector como el escritor, simplemente use el accesorio!

class Person
  attr_accessor :name
end

person = Person.new
person.name = "Dennis"
person.name # => "Dennis"

Funciona de la misma manera! Y adivina qué: la variable de instancia @name en nuestra persona, el objeto se establecerá como cuando lo hicimos manualmente, para que pueda usarlo en otros métodos.

class Person
  attr_accessor :name

  def greeting
    "Hello #{@name}"
  end
end

person = Person.new
person.name = "Dennis"
person.greeting # => "Hello Dennis"

Eso es. Para entender cómo attr_reader, attr_writery attr_accessor En realidad, los métodos generan métodos para ti, lee otras respuestas, libros, documentos de rubí.


2046
2017-12-06 22:11



attr_accessor es solo un metodo. (El enlace debe proporcionar más información sobre cómo funciona: observe los pares de métodos generados, y un tutorial debería mostrarle cómo usarlo).

El truco es que class es no es una definición en Ruby (es "solo una definición" en idiomas como C ++ y Java), pero es un expresión que evalúa. Es durante esta evaluación cuando el attr_accessor se invoca el método que a su vez modifica la clase actual; recuerde el receptor implícito: self.attr_accessor, dónde self es el objeto de clase "abierto" en este punto.

La necesidad de attr_accessor y amigos, es, bueno

  1. Ruby, como Smalltalk, no permite el acceso a variables de instancia fuera de los métodos1 para ese objeto. Es decir, no se puede acceder a las variables de instancia en x.y forma como es común en decir, Java o incluso Python. En Ruby y siempre se toma como un mensaje para enviar (o "método para llamar"). Por lo tanto, la attr_* métodos crean envoltorios que proxy la instancia @variable acceso a través de métodos creados dinámicamente.

  2. Boilerplate apesta

Espero que esto aclare algunos de los pequeños detalles. Feliz codificación.


1 Esto no es estrictamente cierto y hay algunas "técnicas" alrededor de esto, pero no hay soporte de sintaxis para el acceso de "variable de instancia pública".


114
2017-12-06 21:21



attr_accessor es (como @pst declaró) solo un método. Lo que hace es crear más métodos para ti.

Entonces este código aquí:

class Foo
  attr_accessor :bar
end

es equivalente a este código:

class Foo
  def bar
    @bar
  end
  def bar=( new_value )
    @bar = new_value
  end
end

Puede escribir este tipo de método usted mismo en 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

62
2017-12-06 21:29



attr_accessor es muy simple:

attr_accessor :foo

es un atajo para:

def foo=(val)
  @foo = val
end

def foo
  @foo
end

no es más que un getter / setter para un objeto


35
2017-12-06 21:28



Es solo un método que define los métodos getter y setter para variables de instancia. Un ejemplo de implementación sería:

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

17
2017-12-06 21:29



Básicamente falsifican atributos de datos de acceso público, que Ruby no tiene.


16
2017-12-06 21:11



También enfrenté este problema y escribí una respuesta algo larga a esta pregunta. Ya hay algunas buenas respuestas sobre esto, pero cualquiera que busque más aclaraciones, espero que mi respuesta pueda ayudar

Inicializar método

Inicializar le permite establecer datos en una instancia de un objeto al crear la instancia en lugar de tener que establecerlos en una línea separada en su código cada vez que crea una nueva instancia de la clase.

class Person
  attr_accessor :name

  def initialize(name)
    @name = name
  end


  def greeting
    "Hello #{@name}"
  end
end

person = Person.new("Denis")
puts person.greeting

En el código anterior estamos configurando el nombre "Denis" utilizando el método de inicialización pasando Dennis a través del parámetro en Inicializar. Si quisiéramos establecer el nombre sin el método de inicialización, podríamos hacerlo así:

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

En el código anterior, establecemos el nombre invocando el método attr_accessor o setter utilizando person.name, en lugar de establecer los valores al inicializar el objeto.

Ambos "métodos" de hacer este trabajo, pero inicializar nos ahorran tiempo y líneas de código.

Este es el único trabajo de inicialización. No puede invocar inicializar como método. Para obtener realmente los valores de un objeto de instancia, debe usar getters y setters (attr_reader (get), attr_writer (set) y attr_accessor (both)). Vea abajo para más detalles sobre eso.

Getters, Setters (attr_reader, attr_writer, attr_accessor)

Getters, attr_reader: todo el propósito de un getter es devolver el valor de una variable de instancia particular. Visite el código de ejemplo a continuación para obtener un desglose de esto.

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

En el código anterior está llamando a los métodos "item_name" y "quantity" en la instancia de Item "example". El "puts example.item_name" y "example.quantity" devolverán (o "obtendrán") el valor de los parámetros que pasaron al "ejemplo" y los mostrarán en la pantalla.

Afortunadamente en Ruby hay un método inherente que nos permite escribir este código de manera más sucinta; el método attr_reader Vea el código a continuación;

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

Esta sintaxis funciona exactamente de la misma manera, solo nos ahorra seis líneas de código. Imagina si tuvieras 5 estados más atribuibles a la clase Item. El código se alargaría rápidamente.

Setters, attr_writer: Lo que me sorprendió al principio con los métodos setter es que, en mi opinión, parecía realizar una función idéntica al método de inicialización. A continuación explico la diferencia según mi comprensión;

Como se indicó anteriormente, el método de inicialización le permite establecer los valores para una instancia de un objeto en la creación del objeto.

Pero, ¿qué ocurre si desea establecer los valores más adelante, después de crear la instancia, o cambiarlos después de que se hayan inicializado? Este sería un escenario donde usarías un método setter. ESA ES LA DIFERENCIA. No tiene que "establecer" un estado particular cuando está utilizando inicialmente el método attr_writer.

El siguiente código es un ejemplo del uso de un método setter para declarar el valor item_name para esta instancia de la clase Item. Tenga en cuenta que seguimos utilizando el método getter attr_reader para que podamos obtener los valores e imprimirlos en la pantalla, en caso de que desee probar el código usted mismo.

class Item

attr_reader :item_name

  def item_name=(str)
    @item_name = (str)
  end

end

El siguiente código es un ejemplo del uso de attr_writer para acortar nuevamente nuestro código y ahorrar tiempo.

class Item

attr_reader :item_name
attr_writer :item_name

end

item = Item.new
puts item.item_name = "TV"

El siguiente código es una reiteración del ejemplo de inicialización anterior de donde estamos usando initialize para establecer el valor de los objetos de item_name en la creación.

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: realiza las funciones de attr_reader y attr_writer, y le guarda una línea más de código.


12
2017-09-16 01:03



Creo que parte de lo que confunde a los nuevos Rubyists / programadores (como yo) es:

"¿Por qué no puedo simplemente decirle a la instancia que tiene un atributo dado (por ejemplo, nombre) y darle a ese atributo un valor todo en un solo golpe?"

Un poco más generalizado, pero así es como me hizo clic:

Dado:

class Person
end

No hemos definido a la persona como algo que puede tener un nombre o cualquier otro atributo para ese asunto.

Entonces, si nosotros entonces:

baby = Person.new

... y tratar de darles un nombre ...

baby.name = "Ruth"

Obtenemos un error porque, en Rubyland, una clase de objeto Persona no es algo asociado o capaz de tener un "nombre" ... ¡todavía!

PERO podemos usar cualquiera de los métodos dados (ver respuestas anteriores) como una forma de decir, "Una instancia de una clase de Persona (baby) poder ahora tienen un atributo llamado 'nombre', por lo tanto, no solo tenemos una forma sintáctica de obtener y establecer ese nombre, pero tiene sentido que lo hagamos ".

Una vez más, abordar esta pregunta desde un ángulo ligeramente diferente y más general, pero espero que esto ayude a la próxima instancia de la clase Persona que encuentre su camino hacia este hilo.


10
2017-07-10 15:31



Si está familiarizado con el concepto de OOP, debe familiarizarse con el método getter y setter. attr_accessor hace lo mismo en Ruby.

Getter and Setter en General Way

class Person
  def name
    @name
  end

  def name=(str)
    @name = str
  end
end

person = Person.new
person.name = 'Eshaan'
person.name # => "Eshaan"

Método Setter

def name=(val)
  @name = val
end

Método Getter 

def name
  @name
end

Método Getter and Setter en Ruby

class Person
  attr_accessor :name
end

person = Person.new
person.name = "Eshaan"
person.name # => "Eshaan"

10
2018-02-08 07:22



La mayoría de las respuestas anteriores usan código. Esta explicación intenta responder sin usar ningún código:

Explicación por analogía

Las partes externas no pueden acceder a los secretos internos de la CIA

  • Imaginemos un lugar realmente secreto: la CIA. Nadie sabe lo que está sucediendo en la CIA, aparte de las personas dentro de la CIA. En otras palabras, las personas externas no pueden acceder a ninguna información en la CIA. Pero debido a que no es bueno tener una organización que es completamente secreta, cierta información se pone a disposición del mundo exterior, solo cosas que la CIA quiere que todos conozcan, por supuesto: p. el Director de la CIA, cuán ecológico es este departamento en comparación con todos los demás departamentos gubernamentales, etc. Información adicional: p. ¿Quiénes son sus agentes encubiertos en Irak o Afganistán? Este tipo de cosas probablemente seguirá siendo un secreto durante los próximos 150 años.

  • Si se encuentra fuera de la CIA, solo puede acceder a la información que ha puesto a disposición del público. O para usar el lenguaje de la CIA, solo puede acceder a la información que está "limpiada".

  • La información que la CIA quiere poner a disposición del público en general fuera de la CIA se llama: atributos. 

El significado de los atributos de lectura y escritura:

  • En el caso de la CIA, la mayoría de los atributos son "de solo lectura". Esto significa que si eres una fiesta externo a la CIA, puedes pedir: "¿Quién es el director de la CIA?" y obtendrás una respuesta directa. Pero lo que tú no poder hacer con los atributos de "solo lectura" es hacer cambios en los cambios en la CIA. p.ej. no puedes hacer una llamada telefónica y de repente decidir que quiere que Kim Kardashian sea el Director, o que quiere que Paris Hilton sea el Comandante en Jefe.

  • Si los atributos le dieron acceso de "escritura", entonces podría hacer cambios si lo desea, incluso si estaba afuera. De lo contrario, lo único que puedes hacer es leer.

    En otras palabras, los accesores permiten realizar consultas o realizar cambios a organizaciones que de lo contrario no permiten el acceso a personas externas, dependiendo de si los accesores son de acceso de lectura o escritura.

Los objetos dentro de una clase pueden acceder fácilmente entre sí

  • Por otro lado, si ya estabas dentro la CIA, entonces podría llamar fácilmente a su agente de la CIA en Kabul y preguntarle si quiere tomarse una cerveza con el informante local de Kabul después del trabajo. Pero si eres fuera de la CIA, simplemente no tendrá acceso: no podrá saber quiénes son (acceso de lectura) y no podrá cambiar su misión (acceso de escritura).

Exactamente lo mismo con las clases y su capacidad para acceder a variables, propiedades y métodos dentro de ellos. HTH! Cualquier pregunta, por favor pregunte y espero poder aclarar.


10
2018-05-02 04:55