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.

Author: evuez, 2009-11-07

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.

 247
Author: Chuck,
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.

 23
Author: tvanfosson,
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.newque 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
 5
Author: prosseek,
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.

 2
Author: DigitalRoss,
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
 -1
Author: blob,
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.

 -3
Author: LEM Adane,
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