attr_reader - attr_accessor ruby
Diferencia entre @instance_variable y attr_accessor (5)
Debido a que attr_accessor
define métodos, puede llamarlos desde fuera de la clase. Una @variable
solo es accesible desde dentro de la clase.
Acabo de empezar a aprender ruby y no veo la diferencia entre una @instace_variable
y un atributo declarado utilizando attr_accessor
.
¿Cuál es la diferencia entre las siguientes dos clases:
class MyClass
@variable1
end
y
class MyClass
attr_accessor :variable1
end
Busqué muchos tutoriales en línea y todo el mundo usa una notación diferente. ¿Tiene que ver algo con la versión ruby? También busqué algunos hilos viejos en StackOverflow
¿Qué es attr_accessor en ruby?
¿Cuál es la diferencia entre estas dos definiciones de inicialización de clase Ruby?
Pero todavía no puedo averiguar cuál es la mejor manera de usar.
En OOPS tenemos un concepto llamado encapsulación, lo que significa que la representación interna de un objeto generalmente está oculta de la vista fuera de la definición del objeto. Solo el objeto "en sí" puede alterar su propio estado interno. El mundo exterior no puede.
Cada objeto suele definirse por su estado y comportamiento , en ruby las variables de instancia se denominan estado interno o estado del objeto y, de acuerdo con OOPS, ningún otro objeto debe acceder al estado y al hacerlo nos adherimos a la Encapsulación.
ej: class Foo def initialize(bar) @bar = bar end end
Anteriormente, hemos definido una clase Foo y en el método de inicialización hemos inicializado una variable de instancia (atributo) o (propiedad). cuando creamos un nuevo objeto ruby usando el nuevo método, que a su vez llama internamente al método initialize, cuando se ejecuta el método, la variable de instancia @bar se declara e inicializa y se guardará como estado del objeto.
Cada variable de instancia tiene su propio estado interno y es única para el objeto en sí, cada método que definimos en la clase alterará el estado interno del objeto de acuerdo con la definición y el propósito del método. Aquí el método de inicialización hace lo mismo, como crear una nueva variable de instancia.
var object = Foo.new(1)
#<Foo:0x00000001910cc0 @bar=1>
En el fondo, ruby ha creado una variable de instancia (@bar = 1) y ha almacenado el valor como estado del objeto dentro del objeto ''objeto''. podemos verificarlo con el método ''instance_variables'' y esos métodos devuelven una matriz que contiene todas las variables de instancia del objeto de acuerdo con el estado actual del objeto.
object.instance_variables
#[
[0]: @bar
]
Podemos ver la variable de instancia ''@bar'' arriba. que se crea cuando llamamos el método de inicialización en el objeto. esta variable ''@bar'' no debería estar visible (oculta) por defecto y, por lo tanto, no puede ser vista por otras personas desde fuera del objeto, excepto el objeto, desde adentro. Pero, un objeto puede alterar su propio estado interno y esto significa que puede mostrar o cambiar los valores si le damos una forma de hacerlo, estos dos pueden hacerse creando una nueva instancia de métodos en la clase.
cuando queremos ver la variable @bar llamándola, obtenemos un error, ya que por defecto no podemos ver el estado de un objeto.
show = object.bar
#NoMethodError: undefined method `bar'' for #<Foo:0x00000001910cc0 @bar=1>
#from (irb):24
#from /home/.rvm/rubies/ruby-2.0.0-p648/bin/irb:12:in `<main>''
Pero podemos acceder a las variables mediante dos métodos, estos dos se denominan métodos de establecimiento y obtención , que permiten que el objeto muestre o cambie su estado interno (variables de instancia / atributos / propiedades) respectivamente.
class Foo
def bar
@bar
end
def bar=(new_bar)
@bar = new_bar
end
end
Hemos definido los métodos getter (bar) y setter (bar =), podemos nombrarlos de cualquier manera, pero la variable de instancia debe ser la misma que la variable de instancia a la que queremos mostrar o cambiar el valor. los setters y getters son una violación de los conceptos OOPS de una manera pero también son métodos muy poderosos.
cuando definimos los dos métodos volviendo a abrir la clase y definiéndolos, cuando llamamos al objeto con los métodos, podemos ver las variables de instancia (aquí @foo) y cambiar su valor también.
object.bar
1
object.bar=2
2
object.bar
2
Aquí hemos llamado el método bar (getter) que devuelve el valor de @bar y luego hemos llamado bar = method (setter) al que le proporcionamos un new_value como argumento y cambia el valor de la variable de instancia (@bar) y podemos Míralo de nuevo llamando al método de la barra.
En ruby tenemos un método llamado attr_accessor , que combina los métodos set y get, lo definimos por encima de las definiciones de métodos dentro de la clase. Los métodos attr_ * son atajos para crear métodos (setter y getter)
class Foo
attr_accessor :bar
end
tenemos que proporcionar un símbolo (: bar) como argumento al método attr_accessor que crea internamente los métodos setter y getter con los nombres de los métodos como nombre de símbolo suministrado.
Si solo necesitamos un método de obtención, podemos llamar a attr_reader: bar Si necesitamos solo un método de establecimiento, podemos llamar a attr_writer: bar
attr_accessor crea los métodos attr_writer y attr_reader
podemos suministrar tantas variables de instancia como queramos a los métodos attr_ * separados por comas
class Foo
attr_writer :bar
attr_reader :bar
attr_accessor :bar, :baz
end
Las variables de instancia no son visibles fuera de la clase.
class MyClass
def initialize
@message = "Hello"
end
end
msg = MyClass.new
@message
#==> nil # This @message belongs to the global object, not msg
msg.message
#==> NoMethodError: undefined method `message''
msg.@message
#==> SyntaxError: syntax error, unexpected tIVAR
Ahora, siempre puedes hacer esto:
msg.instance_eval { @message }
Pero eso es torpe y engañoso. Buscar en la clase de otra persona puede ser educativo, pero el código de su cliente no debería hacerlo si desea obtener resultados confiables. Por otro lado, si desea que los clientes puedan ver esos valores, no haga que utilicen instance_eval
; en su lugar, define un método que haga el truco:
class MyClass
def message
return @message
end
end
msg.message
# ==> "Hello"
Debido a que muchas veces quieres hacer eso, Ruby proporciona un atajo para que sea más fácil. El siguiente código tiene exactamente el mismo resultado que el código anterior:
class MyClass
attr_reader :message
end
Eso no es un nuevo tipo de variable; Es solo una forma abreviada de definir el método. Puede mirar msg.methods
y ver que ahora tiene un método de message
.
Ahora, ¿qué sucede si quiere permitir que los forasteros no solo vean el valor de una variable de instancia, sino que también lo cambien? Para eso, debe definir un método diferente para la asignación, con a =
en el nombre:
class MyClass
def message=(new_value)
@message = new_value
end
end
msg.message = "Good-bye"
msg.message
# ==> "Good-bye"
Tenga en cuenta que los operadores de asignación son semi-mágicos aquí; A pesar de que hay un espacio entre msg.message
y =
, Ruby todavía sabe que debe llamar al método message=
. Los operadores de combinación como +=
y así sucesivamente también activarán las llamadas al método.
Nuevamente, este es un diseño común, por lo que Ruby también le brinda un atajo:
class MyClass
attr_writer :message
end
Ahora, si usa attr_writer
por sí mismo, obtiene un atributo que se puede modificar, pero no ver. Hay algunos casos de uso extraños en los que eso es lo que quiere, pero la mayoría de las veces, si va a dejar que los forasteros modifiquen la variable, también querrá que ellos puedan leerla. En lugar de tener que declarar tanto attr_reader
como attr_writer
, puede declarar ambos al mismo tiempo:
class MyClass
attr_accessor :message
end
Nuevamente, esto es solo un atajo para definir métodos que le permiten obtener la variable de instancia desde fuera de la clase.
Una variable de instancia no es visible fuera del objeto en el que se encuentra; pero cuando crea un attr_accessor
, crea una variable de instancia y también lo hace visible (y editable) fuera del objeto.
Ejemplo con variable de instancia (no attr_accessor
)
class MyClass
def initialize
@greeting = "hello"
end
end
m = MyClass.new
m.greeting #results in the following error:
#NoMethodError: undefined method `greeting'' for #<MyClass:0x007f9e5109c058 @greeting="hello">
Ejemplo usando attr_accessor
:
class MyClass
attr_accessor :greeting
def initialize
@greeting = "hello"
end
end
m2 = MyClass.new
m2.greeting = "bonjour" # <-- set the @greeting variable from outside the object
m2.greeting #=> "bonjour" <-- didn''t blow up as attr_accessor makes the variable accessible from outside the object
Espero que eso quede claro.
attr_accesor
le proporciona métodos para leer y escribir las variables de instancia. Las variables de instancia están diseñadas para ocultarse del mundo exterior y, por lo tanto, para comunicarnos con ellas, deberíamos tener métodos de acceso attr _ibute.