Variable de instancia: self vs @
Aquí hay un código:
class Person
def initialize(age)
@age = age
end
def age
@age
end
def age_difference_with(other_person)
(self.age - other_person.age).abs
end
protected :age
end
Lo que quiero saber es la diferencia entre usar @age
y self.age
en el método age_difference_with
.
6 answers
Escribiendo @age
accede directamente a la variable de instancia @age
. Escribir self.age
le dice al objeto que se envíe el mensaje age
, que normalmente devolverá la variable de instancia @age
- pero podría hacer cualquier cantidad de otras cosas dependiendo de cómo se implemente el método age
en una subclase dada. Por ejemplo, es posible que tenga una clase MiddleAgedSocialite que siempre informe su edad 10 años más joven de lo que realmente es. O más prácticamente, una clase PersistentPerson podría leer perezosamente esos datos desde un almacén persistente, almacena en caché todos sus datos persistentes en un hash.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-07 15:08:24
La diferencia es que está aislando el uso del método de la implementación del mismo. Si la implementación de la propiedad fuera a cambiar say digamos mantener la fecha de nacimiento y luego calcular la edad basada en la diferencia de tiempo entre ahora y la fecha de nacimiento then entonces el código dependiendo del método no necesita cambiar. Si se utiliza la propiedad directamente, entonces el cambio tendría que propagarse a otras áreas del código. En este sentido, usar la propiedad directamente es más frágil que usar la interfaz provista por la clase.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-07 14:41:52
Se advierte cuando se hereda una clase de Struct.new
que es una forma ordenada de generar un inicializador ( Cómo generar inicializador en Ruby?)
class Node < Struct.new(:value)
def initialize(value)
@value = value
end
def show()
p @value
p self.value # or `p value`
end
end
n = Node.new(30)
n.show()
Volverá
30
nil
Sin embargo, cuando elimine el inicializador, devolverá
nil
30
Con la definición de clase
class Node2
attr_accessor :value
def initialize(value)
@value = value
end
def show()
p @value
p self.value
end
end
Debe proporcionar el constructor.
n2 = Node2.new(30)
n2.show()
Volverá
30
30
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:33
No Hay ninguna diferencia. Sospecho que se hizo solo por el valor documental de ver self.age
y other_person.age
cerca uno del otro.
Supongo que ese uso permite que se escriba un getter real en el futuro, lo que podría hacer algo más complejo que simplemente devolver una variable de instancia, y en ese caso el método no tendría que cambiar.
Pero esa es una abstracción poco probable de la que preocuparse, después de todo, si la implementación del objeto cambió es razonable cambiar otros métodos, en algún momento una simple referencia dentro del objeto en sí es perfectamente razonable.
En cualquier caso, la abstracción de la propiedad age
todavía no explica el uso explícito de self
, ya que simplemente age
también habría invocado al accessor.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-07 14:53:29
La primera respuesta es completamente correcta, pero como un novato relativo, no me quedó claro de inmediato lo que implicaba (¿enviar mensajes a mí mismo? uh huh...). Creo que un ejemplo corto ayudará:
class CrazyAccessors
def bar=(val)
@bar = val - 20 # sets @bar to (input - 20)
end
def bar
@bar
end
def baz=(value)
self.bar = value # goes through `bar=` method, so @bar = (50 - 20)
end
def quux=(value)
@bar = value # sets @bar directly to 50
end
end
obj = CrazyAccessors.new
obj.baz = 50
obj.bar # => 30
obj.quux = 50
obj.bar # => 50
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-04 13:52:17
@age-es definitivamente la variable de instancia age
Auto.age: se refiere a la propiedad de instancia age.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-06 01:26:24