Ruby Language
Ambito e visibilità variabili
Ricerca…
Sintassi
- $ global_variable
- @@ class_variable
- @instance_variable
- local_variable
Osservazioni
Le variabili di classe sono condivise nella gerarchia di classi. Ciò può comportare un comportamento sorprendente.
class A
@@variable = :x
def self.variable
@@variable
end
end
class B < A
@@variable = :y
end
A.variable # :y
Le classi sono oggetti, quindi è possibile utilizzare variabili di istanza per fornire lo stato specifico per ogni classe.
class A
@variable = :x
def self.variable
@variable
end
end
class B < A
@variable = :y
end
A.variable # :x
Variabili locali
Le variabili locali (a differenza delle altre classi variabili) non hanno alcun prefisso
local_variable = "local"
p local_variable
# => local
Il suo ambito dipende da dove è stato dichiarato, non può essere usato al di fuori dell'ambito "contenitori di dichiarazione". Ad esempio, se una variabile locale è dichiarata in un metodo, può essere utilizzata solo all'interno di quel metodo.
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'
Naturalmente, le variabili locali non sono limitate ai metodi, come una regola empirica si potrebbe dire che, non appena si dichiara una variabile all'interno di un do ... end
blocco do ... end
o racchiusa tra parentesi graffe {}
, sarà locale e con scope il blocco è stato dichiarato in
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'
Tuttavia, le variabili locali dichiarate in if
o case
block possono essere utilizzate nello scope parent:
if true
usable = "yay"
end
p usable
# yay
# => "yay"
Mentre le variabili locali non possono essere utilizzate al di fuori del suo blocco di dichiarazione, verranno passate ai blocchi:
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"]
Ma non alle definizioni metodo / classe / modulo
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'
Le variabili utilizzate per gli argomenti di blocco sono (ovviamente) locali al blocco, ma oscureranno le variabili precedentemente definite, senza sovrascriverle.
overshadowed = "sunlight"
["darkness"].each do |overshadowed|
p overshadowed
end
# darkness
# => ["darkness"]
p overshadowed
# "sunlight"
# => "sunlight"
Variabili di classe
Le variabili di classe hanno un ambito di classe, possono essere dichiarate ovunque nella classe. Una variabile sarà considerata una variabile di classe quando è preceduta da @@
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"
Le variabili di classe sono condivise tra classi correlate e possono essere sovrascritte da una classe figlia
class TRex < Dinosaur
@@classification = "Big teeth bird!"
end
TRex.classification
# => "Big teeth bird!"
Dinosaur.classification
# => "Big teeth bird!"
Questo comportamento è indesiderato per la maggior parte del tempo e può essere aggirato utilizzando variabili di istanza a livello di classe.
Le variabili di classe definite all'interno di un modulo non sovrascriveranno le loro variabili di classe comprese le classi:
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!"
Variabili globali
Le variabili globali hanno una portata globale e, quindi, possono essere utilizzate ovunque. Il loro scopo non dipende da dove sono definiti. Una variabile sarà considerata globale, se preceduta da un segno $
.
$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?"
Poiché una variabile globale può essere definita ovunque e sarà visibile ovunque, la chiamata a una variabile globale "non definita" restituirà nil anziché generare un errore.
p $undefined_var
# nil
# => nil
Sebbene le variabili globali siano facili da usare, il suo utilizzo è fortemente scoraggiato a favore delle costanti.
Variabili di istanza
Le variabili di istanza hanno un ambito a livello di oggetto, possono essere dichiarate ovunque nell'oggetto, tuttavia una variabile di istanza dichiarata a livello di classe, sarà visibile solo nell'oggetto classe. Una variabile sarà considerata una variabile di istanza quando è preceduta da @
. Le variabili di istanza vengono utilizzate per impostare e ottenere attributi di oggetti e restituiranno zero se non definite.
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"
Non è possibile accedere alla variabile di istanza dichiarata a livello di classe a livello di oggetto:
dino_1.try_to_speak
# => nil
Tuttavia, abbiamo usato la variabile di istanza @base_sound
per istanziare il suono quando non viene passato alcun suono al nuovo metodo:
dino_1.speak
# => "rawwr"
Le variabili di istanza possono essere dichiarate ovunque nell'oggetto, anche all'interno di un blocco:
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
Le variabili di istanza non sono condivise tra istanze della stessa classe
dino_2.sound_length
# => nil
Questo può essere usato per creare variabili di livello di classe, che non verranno sovrascritte da una classe figlio, poiché le classi sono anche oggetti in 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"