Ruby Language
Alcance variable y visibilidad
Buscar..
Sintaxis
- $ global_variable
- @@ class_variable
- @Instancia variable
- variable local
Observaciones
Las variables de clase se comparten en la jerarquía de clases. Esto puede resultar en un comportamiento sorprendente.
class A
@@variable = :x
def self.variable
@@variable
end
end
class B < A
@@variable = :y
end
A.variable # :y
Las clases son objetos, por lo que las variables de instancia se pueden usar para proporcionar un estado que sea específico para cada clase.
class A
@variable = :x
def self.variable
@variable
end
end
class B < A
@variable = :y
end
A.variable # :x
Variables locales
Las variables locales (a diferencia de las otras clases de variables) no tienen ningún prefijo
local_variable = "local"
p local_variable
# => local
Su alcance depende de donde se ha declarado, no se puede usar fuera del alcance de "contenedores de declaración". Por ejemplo, si una variable local se declara en un método, solo se puede usar dentro de ese método.
def some_method
method_scope_var = "hi there"
p method_scope_var
end
some_method
# hi there
# => hi there
method_scope_var
# NameError: undefined local variable or method `method_scope_var'
Por supuesto, las variables locales no se limitan a los métodos, como regla de oro podría decir que, tan pronto como declare una variable dentro de un bloque do ... end
o envuelto entre llaves {}
, será local y estará dentro del alcance de El bloque ha sido declarado en.
2.times do |n|
local_var = n + 1
p local_var
end
# 1
# 2
# => 2
local_var
# NameError: undefined local variable or method `local_var'
Sin embargo, las variables locales declaradas en if
o los bloques de case
se pueden usar en el ámbito principal:
if true
usable = "yay"
end
p usable
# yay
# => "yay"
Si bien las variables locales no pueden utilizarse fuera de su bloque de declaración, se transmitirán a los bloques:
my_variable = "foo"
my_variable.split("").each_with_index do |char, i|
puts "The character in string '#{my_variable}' at index #{i} is #{char}"
end
# The character in string 'foo' at index 0 is f
# The character in string 'foo' at index 1 is o
# The character in string 'foo' at index 2 is o
# => ["f", "o", "o"]
Pero no a las definiciones de método / clase / módulo
my_variable = "foo"
def some_method
puts "you can't use the local variable in here, see? #{my_variable}"
end
some_method
# NameError: undefined local variable or method `my_variable'
Las variables utilizadas para los argumentos de bloque son (por supuesto) locales al bloque, pero eclipsarán las variables previamente definidas, sin sobrescribirlas.
overshadowed = "sunlight"
["darkness"].each do |overshadowed|
p overshadowed
end
# darkness
# => ["darkness"]
p overshadowed
# "sunlight"
# => "sunlight"
Variables de clase
Las variables de clase tienen un amplio alcance de clase, se pueden declarar en cualquier parte de la clase. Una variable se considerará una variable de clase cuando se prefija con @@
class Dinosaur
@@classification = "Like a Reptile, but like a bird"
def self.classification
@@classification
end
def classification
@@classification
end
end
dino = Dinosaur.new
dino.classification
# => "Like a Reptile, but like a bird"
Dinosaur.classification
# => "Like a Reptile, but like a bird"
Las variables de clase se comparten entre clases relacionadas y se pueden sobrescribir de una clase secundaria
class TRex < Dinosaur
@@classification = "Big teeth bird!"
end
TRex.classification
# => "Big teeth bird!"
Dinosaur.classification
# => "Big teeth bird!"
Este comportamiento no es deseado la mayor parte del tiempo y se puede sortear mediante el uso de variables de instancia de nivel de clase.
Las variables de clase definidas dentro de un módulo no sobrescribirán sus variables de clase incluidas las clases:
module SomethingStrange
@@classification = "Something Strange"
end
class DuckDinosaur < Dinosaur
include SomethingStrange
end
DuckDinosaur.class_variables
# => [:@@classification]
SomethingStrange.class_variables
# => [:@@classification]
DuckDinosaur.classification
# => "Big teeth bird!"
Variables globales
Las variables globales tienen un alcance global y, por lo tanto, se pueden utilizar en todas partes. Su alcance no depende de donde se definan. Una variable se considerará global, cuando se prefija con un signo $
.
$i_am_global = "omg"
class Dinosaur
def instance_method
p "global vars can be used everywhere. See? #{$i_am_global}, #{$another_global_var}"
end
def self.class_method
$another_global_var = "srsly?"
p "global vars can be used everywhere. See? #{$i_am_global}"
end
end
Dinosaur.class_method
# "global vars can be used everywhere. See? omg"
# => "global vars can be used everywhere. See? omg"
dinosaur = Dinosaur.new
dinosaur.instance_method
# "global vars can be used everywhere. See? omg, srsly?"
# => "global vars can be used everywhere. See? omg, srsly?"
Dado que una variable global se puede definir en todas partes y será visible en todas partes, llamar a una variable global "indefinida" devolverá nil en lugar de generar un error.
p $undefined_var
# nil
# => nil
Si bien las variables globales son fáciles de usar, su uso está fuertemente desaconsejado a favor de las constantes.
Variables de instancia
Las variables de instancia tienen un amplio alcance de objeto, se pueden declarar en cualquier parte del objeto, sin embargo, una variable de instancia declarada en el nivel de clase, solo será visible en el objeto de clase. Una variable se considerará una variable de instancia cuando se prefija con @
. Las variables de instancia se utilizan para establecer y obtener atributos de un objeto y devolverán cero si no se definen.
class Dinosaur
@base_sound = "rawrr"
def initialize(sound = nil)
@sound = sound || self.class.base_sound
end
def speak
@sound
end
def try_to_speak
@base_sound
end
def count_and_store_sound_length
@sound.chars.each_with_index do |char, i|
@sound_length = i + 1
p "#{char}: #{sound_length}"
end
end
def sound_length
@sound_length
end
def self.base_sound
@base_sound
end
end
dino_1 = Dinosaur.new
dino_2 = Dinosaur.new "grrr"
Dinosaur.base_sound
# => "rawrr"
dino_2.speak
# => "grrr"
No se puede acceder a la variable de instancia declarada en el nivel de clase en el nivel de objeto:
dino_1.try_to_speak
# => nil
Sin embargo, usamos la variable de instancia @base_sound
para crear una instancia del sonido cuando no se pasa ningún sonido al nuevo método:
dino_1.speak
# => "rawwr"
Las variables de instancia se pueden declarar en cualquier parte del objeto, incluso dentro de un bloque:
dino_1.count_and_store_sound_length
# "r: 1"
# "a: 2"
# "w: 3"
# "r: 4"
# "r: 5"
# => ["r", "a", "w", "r", "r"]
dino_1.sound_length
# => 5
Las variables de instancia no se comparten entre instancias de la misma clase
dino_2.sound_length
# => nil
Esto se puede usar para crear variables de nivel de clase, que no serán sobrescritas por una clase hija, ya que las clases también son objetos en Ruby.
class DuckDuckDinosaur < Dinosaur
@base_sound = "quack quack"
end
duck_dino = DuckDuckDinosaur.new
duck_dino.speak
# => "quack quack"
DuckDuckDinosaur.base_sound
# => "quack quack"
Dinosaur.base_sound
# => "rawrr"