Ruby Language
Portée et visibilité variables
Recherche…
Syntaxe
- $ global_variable
- @@ class_variable
- @instance_variable
- variable locale
Remarques
Les variables de classe sont partagées dans la hiérarchie des classes. Cela peut entraîner un comportement surprenant.
class A
@@variable = :x
def self.variable
@@variable
end
end
class B < A
@@variable = :y
end
A.variable # :y
Les classes sont des objets, donc les variables d'instance peuvent être utilisées pour fournir un état spécifique à chaque classe.
class A
@variable = :x
def self.variable
@variable
end
end
class B < A
@variable = :y
end
A.variable # :x
Variables locales
Les variables locales (contrairement aux autres classes de variables) n'ont pas de préfixe
local_variable = "local"
p local_variable
# => local
Son étendue dépend de l'endroit où il a été déclaré, il ne peut pas être utilisé en dehors du périmètre "déclaration conteneurs". Par exemple, si une variable locale est déclarée dans une méthode, elle ne peut être utilisée que dans cette méthode.
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'
Bien sûr, les variables locales ne se limitent pas aux méthodes, en règle générale , vous pouvez dire que, dès que vous déclarez une variable à l' intérieur d' un do ... end
bloc ou wrapped accolades {}
, il sera local et à SCOPED le bloc dans lequel il a été déclaré
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'
Cependant, les variables locales déclarées dans if
ou les blocs de case
peuvent être utilisés dans la parent-scope:
if true
usable = "yay"
end
p usable
# yay
# => "yay"
Bien que les variables locales ne puissent pas être utilisées en dehors de son bloc de déclaration, elles seront transmises à des blocs:
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"]
Mais pas aux définitions de méthode / classe / module
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'
Les variables utilisées pour les arguments de bloc sont (naturellement) locales au bloc, mais occulteront les variables précédemment définies, sans les écraser.
overshadowed = "sunlight"
["darkness"].each do |overshadowed|
p overshadowed
end
# darkness
# => ["darkness"]
p overshadowed
# "sunlight"
# => "sunlight"
Variables de classe
Les variables de classe ont une portée étendue, elles peuvent être déclarées n'importe où dans la classe. Une variable sera considérée comme une variable de classe avec le préfixe @@
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"
Les variables de classe sont partagées entre les classes associées et peuvent être écrasées à partir d'une classe enfant
class TRex < Dinosaur
@@classification = "Big teeth bird!"
end
TRex.classification
# => "Big teeth bird!"
Dinosaur.classification
# => "Big teeth bird!"
Ce comportement est indésirable la plupart du temps et peut être contourné en utilisant des variables d'instance de niveau classe.
Les variables de classe définies dans un module n'écrasent pas leurs variables de classe incluant les classes:
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
Les variables globales ont une portée mondiale et peuvent donc être utilisées partout. Leur portée ne dépend pas de l'endroit où ils sont définis. Une variable sera considérée comme globale lorsqu'elle est préfixée par un signe $
.
$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?"
Comme une variable globale peut être définie partout et sera visible partout, l'appel d'une variable globale "non définie" renverra zéro au lieu de générer une erreur.
p $undefined_var
# nil
# => nil
Bien que les variables globales soient faciles à utiliser, leur utilisation est fortement déconseillée en faveur des constantes.
Variables d'instance
Les variables d'instance ont une portée étendue à l'objet, elles peuvent être déclarées n'importe où dans l'objet, cependant une variable d'instance déclarée au niveau de la classe ne sera visible que dans l'objet de classe. Une variable sera considérée comme une variable d'instance avec le préfixe @
. Les variables d’instance permettent de définir et d’obtenir des attributs d’objet et renvoient zéro si elles ne sont pas définies.
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"
La variable d'instance déclarée au niveau de la classe n'est pas accessible au niveau de l'objet:
dino_1.try_to_speak
# => nil
Cependant, nous avons utilisé la variable d’instance @base_sound
pour instancier le son quand aucun son n’est transmis à la nouvelle méthode:
dino_1.speak
# => "rawwr"
Les variables d'instance peuvent être déclarées n'importe où dans l'objet, même à l'intérieur d'un bloc:
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
Les variables d'instance ne sont pas partagées entre les instances de la même classe
dino_2.sound_length
# => nil
Cela peut être utilisé pour créer des variables de niveau classe, qui ne seront pas écrasées par une classe enfant, car les classes sont également des objets dans 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"