sirve - ruby tutorial
¿Qué es attr_accessor en ruby? (18)
Estoy teniendo dificultades para entender attr_accessor
en Ruby. ¿Puede alguien explicarme esto?
Atributos y métodos de acceso
Los atributos son componentes de clase a los que se puede acceder desde fuera del objeto. Son conocidos como propiedades en muchos otros lenguajes de programación. Se puede acceder a sus valores utilizando la "notación de puntos", como en object_name.attribute_name. A diferencia de Python y algunos otros lenguajes, Ruby no permite acceder a las variables de instancia directamente desde fuera del objeto.
class Car
def initialize
@wheels = 4 # This is an instance variable
end
end
c = Car.new
c.wheels # Output: NoMethodError: undefined method `wheels'' for #<Car:0x00000000d43500>
En el ejemplo anterior, c es una instancia (objeto) de la clase Car. Intentamos sin éxito leer el valor de la variable de instancia de ruedas desde fuera del objeto. Lo que sucedió es que Ruby intentó llamar a un método llamado ruedas dentro del objeto c, pero no se definió tal método. En resumen, object_name.attribute_name intenta llamar a un método llamado attribute_name dentro del objeto. Para acceder al valor de la variable de las ruedas desde el exterior, necesitamos implementar un método de instancia con ese nombre, que devolverá el valor de esa variable cuando se llame. Eso se llama un método de acceso. En el contexto de programación general, la forma habitual de acceder a una variable de instancia desde fuera del objeto es implementar métodos de acceso, también conocidos como métodos de obtención y establecimiento. Un captador permite que el valor de una variable definida dentro de una clase se lea desde el exterior y un configurador permite que se escriba desde el exterior.
En el siguiente ejemplo, hemos agregado métodos de captador y definidor a la clase Coche para acceder a la variable de las ruedas desde fuera del objeto. Esta no es la "forma de Ruby" de definir a los getters y setters; solo sirve para ilustrar lo que hacen los métodos de captador y definidor.
class Car
def wheels # getter method
@wheels
end
def wheels=(val) # setter method
@wheels = val
end
end
f = Car.new
f.wheels = 4 # The setter method was invoked
f.wheels # The getter method was invoked
# Output: => 4
El ejemplo anterior funciona y un código similar se usa comúnmente para crear métodos de obtención y establecimiento en otros idiomas. Sin embargo, Ruby proporciona una forma más sencilla de hacer esto: tres métodos incorporados llamados attr_reader, attr_writer y attr_acessor. El método attr_reader hace que una variable de instancia sea legible desde el exterior, attr_writer hace que se pueda escribir, y attr_acessor lo hace legible y se puede escribir.
El ejemplo anterior se puede reescribir así.
class Car
attr_accessor :wheels
end
f = Car.new
f.wheels = 4
f.wheels # Output: => 4
En el ejemplo anterior, el atributo ruedas se podrá leer y escribir desde fuera del objeto. Si en lugar de attr_accessor, usáramos attr_reader, sería de solo lectura. Si utilizamos attr_writer, sería de solo escritura. Esos tres métodos no son captadores y definidores en sí mismos, sino que, cuando se les llama, crean métodos para ellos. Son métodos que dinámicamente (programáticamente) generan otros métodos; Eso se llama metaprogramación.
El primer ejemplo (más largo), que no emplea los métodos incorporados de Ruby, solo debe usarse cuando se requiere un código adicional en los métodos de obtención y configuración. Por ejemplo, un método de establecimiento puede necesitar validar datos o hacer algún cálculo antes de asignar un valor a una variable de instancia.
Es posible acceder (leer y escribir) variables de instancia desde fuera del objeto, utilizando los métodos incorporados instance_variable_get y instance_variable_set. Sin embargo, esto rara vez es justificable y, por lo general, es una mala idea, ya que el hecho de evitar la encapsulación tiende a causar todo tipo de estragos.
Básicamente, falsifican atributos de datos de acceso público, que Ruby no tiene.
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 determinado (por ejemplo, nombre) y darle a ese atributo un valor de una sola vez?"
Un poco más generalizado, pero así es como me hizo clic:
Dado:
class Person
end
No hemos definido a Persona como algo que puede tener un nombre o cualquier otro atributo para esa materia.
Así que si nosotros entonces:
baby = Person.new
... y tratar de darles un nombre ...
baby.name = "Ruth"
Recibimos 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 manera de decir: "Una instancia de una clase de persona ( baby
) ahora puede tener un atributo llamado ''nombre'', por lo tanto, no solo tenemos una forma sintáctica de obtener y establecer ese nombre, pero tiene sentido para nosotros hacerlo ".
Nuevamente, 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.
Define un atributo con nombre para este módulo, donde el nombre es symbol.id2name, creando una variable de instancia (@name) y un método de acceso correspondiente para leerlo. También crea un método llamado nombre = para establecer el atributo.
module Mod
attr_accessor(:one, :two)
end
Mod.instance_methods.sort #=> [:one, :one=, :two, :two=]
Digamos que tienes una Person
clase.
class Person
end
person = Person.new
person.name # => no method error
Obviamente nunca definimos el name
método. 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 el segundo se llama escritor . No creamos al escritor todavía, así que hagamos eso.
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 la variable de instancia @name
usando métodos de lector y escritor. Excepto, esto se hace con tanta frecuencia, ¿por qué perder el tiempo escribiendo estos métodos cada vez? Podemos hacerlo más fácil.
class Person
attr_reader :name
attr_writer :name
end
Incluso esto puede volverse repetitivo. Cuando quiera que tanto el lector como el escritor solo utilicen accessor!
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 nuestro objeto de persona se establecerá como cuando lo hicimos manualmente, para que puedas usarla 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 los attr_reader
, attr_writer
y attr_accessor
realmente generan métodos para usted, lea otras respuestas, libros, documentos ruby.
En pocas palabras, definirá un definidor y un captador para la clase.
Tenga en cuenta que
attr_reader :v is equivalant to
def v
@v
end
attr_writer :v is equivalant to
def v=(value)
@v=value
end
Asi que
attr_accessor :v which means
attr_reader :v; attr_writer :v
son equivalentes para definir un colocador y un captador para la clase.
Es solo un método que define los métodos getter y setter para las variables de instancia. Una implementación de ejemplo 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
Hmmm Muchas buenas respuestas. Aquí están mis pocos centavos.
attr_accessor
es un método simple que nos ayuda a limpiar ( SECAR ) los métodos repetidores degetter and setter
.Para que podamos centrarnos más en escribir lógica de negocios y no preocuparnos por los instaladores y captadores.
La funcionalidad principal de attr_accessor sobre los otros es la capacidad de acceder a datos de otros archivos.
Por lo general, tendría attr_reader o attr_writer, pero la buena noticia es que Ruby le permite combinar estos dos juntos con attr_accessor. Lo considero como mi método de ir porque es más completo o versátil. Además, mira con atención que en Rails, esto se elimina porque lo hace por ti en el back-end. En otras palabras, es mejor usar attr_acessor sobre los otros dos porque no tiene que preocuparse por ser específico, el descriptor de acceso lo cubre todo. Sé que esto es más una explicación general pero me ayudó como principiante.
Espero que esto haya ayudado!
La mayoría de las respuestas anteriores utilizan código. Esta explicación intenta responderla sin usar ningún código:
Explicación vía 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 como no es bueno tener una organización que sea completamente secreta, cierta información está disponible para el mundo exterior, solo las cosas que la CIA quiere que todos conozcan, por ejemplo: el Director de la CIA, qué tan amigable para el medio ambiente es este departamento. a todos los demás departamentos gubernamentales, etc. Otra información: por ejemplo, quiénes son sus agentes encubiertos en Irak o Afganistán, este tipo de cosas probablemente se mantendrá en secreto durante los próximos 150 años.
Si está 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á "borrada".
La información que la CIA quiere poner a disposición del público en general fuera de la CIA se denomina atributos.
El significado de los atributos de lectura y escritura:
En el caso de la CIA, la mayoría de los atributos son "solo lectura". Esto significa que si usted es una parte ajena a la CIA, puede preguntar: "¿quién es el director de la CIA?" y obtendrás una respuesta directa. Pero lo que no puede hacer con los atributos de "solo lectura" es hacer cambios en la CIA. por ejemplo, no puede hacer una llamada telefónica y de repente decide que desea que Kim Kardashian sea el Director, o que desea 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 estuviera afuera. De lo contrario, lo único que puedes hacer es leer.
En otras palabras, los accesores le permiten realizar consultas, o realizar cambios, a organizaciones que de otro modo no permiten el acceso de personas externas, según si los accesores son de acceso de lectura o de escritura.
Los objetos dentro de una clase pueden acceder fácilmente entre sí
- Por otro lado, si ya estaba dentro de la CIA, podría llamar fácilmente a su agente de la CIA en Kabul y preguntarle si quiere tomar una cerveza con el informante local de Kabul después del trabajo. Pero si está fuera de la CIA, simplemente no se le dará 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 ellas. HTH! Cualquier pregunta, por favor pregunte y espero poder aclarar.
Otra forma de entenderlo es averiguar qué código de error elimina al tener attr_accessor
.
Ejemplo:
class BankAccount
def initialize( account_owner )
@owner = account_owner
@balance = 0
end
def deposit( amount )
@balance = @balance + amount
end
def withdraw( amount )
@balance = @balance - amount
end
end
Los siguientes métodos están disponibles:
$ bankie = BankAccout.new("Iggy")
$ bankie
$ bankie.deposit(100)
$ bankie.withdraw(5)
Los siguientes métodos arrojan error:
$ bankie.owner #undefined method `owner''...
$ bankie.balance #undefined method `balance''...
owner
y el balance
no son, técnicamente, un método , sino un atributo. La clase BankAccount no tiene def owner
def balance
y def balance
. Si lo hace, entonces puede usar los dos comandos a continuación. Pero esos dos métodos no están ahí. Sin embargo, puede acceder a los atributos como si tuviera acceso a un método a través de attr_accessor
!! De ahí la palabra attr_accessor
. Atributo. Accesorio Accede a atributos como usted accedería a un método.
Agregando attr_accessor :balance, :owner
permite leer y escribir balance
y el "método" de owner
. Ahora puedes usar los 2 últimos métodos.
$ bankie.balance
$ bankie.owner
Para resumir, un atributo accessor aka attr_accessor le da dos métodos libres.
Como en Java se les llama getters y setters.
Muchas respuestas han mostrado buenos ejemplos, así que seré breve.
#el_atributo
y
# the_attribute =
En los documentos antiguos de ruby, una etiqueta hash # significa un método. También podría incluir un prefijo de nombre de clase ... MyClass # my_method
Si está familiarizado con el concepto OOP, debe estar familiarizado con el método de obtención y configuración. attr_accessor hace lo mismo en Ruby.
Getter y Setter en general.
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 y Setter en Ruby.
class Person
attr_accessor :name
end
person = Person.new
person.name = "Eshaan"
person.name # => "Eshaan"
Simplemente attr-accessor
crea los métodos getter
y setter
para los atributos especificados
También enfrenté este problema y escribí una respuesta bastante larga a esta pregunta. Ya hay algunas respuestas geniales sobre esto, pero cualquiera que busque más aclaraciones, espero que mi respuesta pueda ayudar.
Método de inicialización
Inicializar le permite establecer datos en una instancia de un objeto al crear la instancia en lugar de tener que configurarlos en una línea separada en su código cada vez que cree 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" usando el método de inicialización pasando a 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 de establecimiento attr_accessor usando person.name, en lugar de establecer los valores al inicializar el objeto.
Ambos "métodos" de hacer este trabajo, pero la inicialización nos ahorra tiempo y líneas de código.
Este es el único trabajo de inicializar. No se puede llamar al inicializar como método. Para obtener realmente los valores de un objeto de instancia, debe usar los métodos de obtención y configuración (attr_reader (get), attr_writer (set) y attr_accessor (ambos)). Vea a continuación para más detalles sobre esos.
Getters, Setters (attr_reader, attr_writer, attr_accessor)
Getters, attr_reader: el propósito completo de un getter es devolver el valor de una variable de instancia particular. Visite el código de muestra a continuación para obtener un desglose sobre 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 "cantidad" en la instancia del artículo "ejemplo". Los valores "poner example.item_name" y "example.quantity" devolverán (u "obtendrán") el valor de los parámetros que se pasaron al "ejemplo" y los mostrarán en la pantalla.
Por suerte, 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 de abajo;
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 que nos ahorra seis líneas de código. Imagínese si tuviera 5 estados más atribuibles a la clase de artículo? El código se haría largo rápidamente.
Setters, attr_writer: Lo que me sorprendió al principio con los métodos de setter es que a mis ojos parecía realizar una función idéntica al método de inicialización. A continuación explico la diferencia en función de 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é sucede 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 en el que utilizarías un método de establecimiento. Esa es la diferencia No tiene que "establecer" un estado particular cuando está utilizando el método attr_writer inicialmente.
El código a continuación es un ejemplo del uso de un método de establecimiento para declarar el valor item_name para esta instancia de la clase de artículo. Tenga en cuenta que continuamos 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 por su cuenta.
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 una vez más 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 código a continuación es una reiteración del ejemplo de inicialización anterior de donde estamos usando inicializar para establecer el valor de los objetos de item_name en el momento de 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, lo que le ahorra una línea más de código.
attr_accessor es solo un método . (El enlace debe proporcionar más información acerca de cómo funciona: observe los pares de métodos generados y un tutorial le mostrará cómo usarlo).
El truco es que la class
no es una definición en Ruby (es "solo una definición" en lenguajes como C ++ y Java), pero es una expresión que evalúa . Es durante esta evaluación cuando se invoca el método attr_accessor
que a su vez modifica la clase actual; recuerde el receptor implícito: self.attr_accessor
, donde self
es el objeto de clase "abierto" en este punto.
La necesidad de attr_accessor
y amigos, es, bueno:
Ruby, como Smalltalk, no permite el acceso a las variables de instancia fuera de los métodos 1 para ese objeto. Es decir, no se puede acceder a las variables de instancia en la forma
xy
como es común en, por ejemplo, Java o incluso Python. En Rubyy
siempre se toma como un mensaje para enviar (o "método para llamar"). Por lo tanto, los métodosattr_*
crean envolturas que representan la instancia del acceso@variable
a través de métodos creados dinámicamente.Caldera chupa
Espero que esto aclare algunos de los pequeños detalles. Feliz codificacion
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".
attr_accessor
es (como se indica en @pst) solo un método. Lo que hace es crear más métodos para ti.
Así que 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
Puedes escribir este tipo de método tú 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
attr_accessor
es muy simple:
attr_accessor :foo
es un atajo para:
def foo=(val)
@foo = val
end
def foo
@foo
end
no es nada más que un captador / definidor para un objeto