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 age_difference_with method.

    Escribir @age accede directamente a la variable de instancia @age . Escribir self.age le dice al objeto que se envíe la age del mensaje, que generalmente devolverá la variable de instancia @age , pero podría hacer cualquier cantidad de cosas dependiendo de cómo se implemente el método de age en una determinada subclase. Por ejemplo, puede tener una clase MiddleAgedSocialite que siempre informe que su edad es 10 años más joven de lo que realmente es. O más prácticamente, una clase PersistentPerson podría leer perezosamente los datos de una tienda persistente, almacenar en caché todos sus datos persistentes en un hash.

    La diferencia es que está aislando el uso del método de la implementación del mismo. Si la implementación de la propiedad cambiara, por ejemplo, para mantener la fecha de nacimiento y luego calcular la edad en función de la diferencia en el tiempo entre ahora y la fecha de nacimiento, entonces no es necesario cambiar el código según el método. Si utilizó la propiedad directamente, entonces el cambio necesitaría propagarse a otras áreas del código. En este sentido, usar la propiedad directamente es más frágil que utilizar la interfaz proporcionada por la clase.

    Tenga cuidado cuando hereda una clase de Struct.new que es una buena manera de generar un intializador ( ¿Cómo generar el 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() 

    regresará

     30 nil 

    Sin embargo, cuando elimina el inicializador, regresará

     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 

    Deberías proporcionar el constructor.

     n2 = Node2.new(30) n2.show() 

    regresará

     30 30 

    No hay ninguna diferencia Sospecho que se hizo solo por el valor documental de ver a self.age y other_person.age uno cerca 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 punto una simple referencia dentro del objeto en sí es perfectamente razonable.

    En cualquier caso, la abstracción de la propiedad de la age todavía no explica el uso explícito de self , ya que simplemente la age simple también habría invocado el descriptor de acceso.

    La primera respuesta es totalmente correcta, pero como un novato relativo, no me fue inmediatamente claro lo que implicaba (¿enviar mensajes a mí mismo? ¿Eh? …). Creo que un breve ejemplo 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 

    @age – es definitivamente la edad de la variable de instancia

    self.age: hace referencia a la antigüedad de la propiedad de la instancia.