Entendiendo el ‘ yo ‘ en Ruby
Hoy me gustaría hablar de self
. Si has estado programando Ruby por un tiempo, es probable que hayas interiorizado la idea de self
. Cada vez que lees o escribes un programa, self
está en el fondo de tu mente.
Pero para rubistas con menos experiencia, self
puede ser desconcertante. Siempre está cambiando, pero nunca se muestra explícitamente en el código. Sólo se espera que lo sepas.
Muchos de los problemas a los que se enfrentan los principiantes son causados por no comprender self
. Si alguna vez ha» perdido » una variable de instancia o se ha preguntado qué datos son visibles para un mixin, es porque no entendió self
en ese contexto.
En esta publicación, vamos a ver self
en una variedad de situaciones cotidianas.
¿Qué es self?
Es posible que haya escuchado a la gente decir que todo en Ruby es un objeto. Si eso es cierto, significa que cada pieza de código que escribes «pertenece» a algún objeto.
self
es una variable especial que apunta al objeto que «posee» el código que se está ejecutando actualmente. Ruby usa self
en todas partes:
- Por ejemplo, variables:
@myvar
- Para buscar métodos y constantes
- Al definir métodos, clases y módulos.
En teoría, self
es bastante obvio. Pero en la práctica, es fácil que aparezcan situaciones complicadas. Por eso escribí este post.
Ejemplos de uno mismo
Vamos a pasar por varios ejemplos ahora. Si los primeros parecen demasiado básicos para ti, sigue leyendo. Se hacen más avanzados.
Dentro de un método de instancia
En el código siguiente, reflect
es un método de instancia. Pertenece al objeto que creamos a través de Ghost.new
. Así que self
apunta a ese objeto.
class Ghost def reflect self endendg = Ghost.newg.reflect == g # => true
Dentro de un método de clase
Para este ejemplo, reflect
es un método de clase de Ghost
. Con los métodos de clase, la propia clase «posee» el método. self
apunta a la clase.
class Ghost def self.reflect self endendGhost.reflect == Ghost # => true
Funciona de la misma manera con los métodos de» clase » dentro de los módulos. Por ejemplo:
module Ghost def self.reflect self endend Ghost.reflect == Ghost # => true
Recuerde, las clases y los módulos se tratan como objetos en Ruby. Así que este comportamiento no es tan diferente del comportamiento del método de instancia que vimos en el primer ejemplo.
Dentro de una definición de clase o módulo
Una característica de Ruby que lo hace tan adecuado para frameworks como Rails es que puede ejecutar código arbitrario dentro de definiciones de clase y módulo. Cuando pones código dentro de una definición de clase / módulo, se ejecuta como cualquier otro código Ruby. La única diferencia real es el valor de self
.
Como puede ver a continuación, self
apunta a la clase o módulo que se está definiendo.
class Ghost self == Ghost # => trueend module Mummy self == Mummy # => trueend
Dentro de los métodos mixin
Los métodos mezclados se comportan igual que los métodos de clase o instancia» normales » cuando se trata de self
. Esto tiene sentido. De lo contrario, el mixin no podría interactuar con la clase en la que lo mezclaste.
Métodos de instancia
Aunque el método reflect
se definió en el módulo, su self
es la instancia de la clase en la que se mezcló.
module Reflection def reflect self endend class Ghost include Reflectionendg = Ghost.newg.reflect == g # => true
Métodos de clase
Cuando extend
una clase para mezclar en métodos de clase, self
se comporta exactamente como lo hace en métodos de clase normales.
module Reflection def reflect self endend class Ghost extend ReflectionendGhost.reflect == Ghost # => true
Dentro de la metaclase
Es probable que haya visto este popular atajo para definir muchos métodos de clase a la vez.
class Ghost class << self def method1 end def method2 end endend
La sintaxis class << foo
es bastante interesante. Le permite acceder a la metaclase de un objeto, que también se llama «clase singleton» o «clase propia».»Planeo cubrir las metaclases más profundamente en un futuro post. Pero por ahora, solo necesita saber que la metaclase es donde Ruby almacena métodos que son únicos para un objeto específico.
Si accede a self
desde el bloque class << foo
, obtiene la metaclase.
class << "test" puts self.inspectend# => #<Class:#<String:0x007f8de283bd88>
Fuera de cualquier clase
Si está ejecutando código fuera de cualquier clase, Ruby todavía proporciona self
. Apunta a «principal», que es una instancia de Object
:
puts self.inspect # => main