Ruby Language
Variabelt omfattning och synlighet
Sök…
Syntax
- $ global_variable
- @@ class_variable
- @instance_variable
- local_variable
Anmärkningar
Klassvariabler delas i klasshierarkin. Detta kan resultera i överraskande beteende.
class A
@@variable = :x
def self.variable
@@variable
end
end
class B < A
@@variable = :y
end
A.variable # :y
Klasser är objekt, så instansvariabler kan användas för att ge tillstånd som är specifikt för varje klass.
class A
@variable = :x
def self.variable
@variable
end
end
class B < A
@variable = :y
end
A.variable # :x
Lokala variabler
Lokala variabler (till skillnad från de andra variabla klasserna) har inga prefix
local_variable = "local"
p local_variable
# => local
Omfånget är beroende av var det har deklarerats, det kan inte användas utanför "deklarationsbehållares" räckvidd. Om till exempel en lokal variabel deklareras i en metod kan den bara användas inuti den metoden.
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'
Naturligtvis är lokala variabler inte begränsade till metoder, som en tumregel kan du säga att så snart du förklarar en variabel inuti ett do ... end
slutblock eller inslaget i lockiga hängslen {}
kommer det att vara lokalt och scoped till det block som det har förklarats i.
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'
Lokala variabler som deklareras i if
eller case
block kan dock användas i överordnade omfång:
if true
usable = "yay"
end
p usable
# yay
# => "yay"
Medan lokala variabler inte kan användas utanför dess deklarationsblock, kommer de att överföras till block:
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"]
Men inte definitioner av metod / klass / modul
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'
Variablerna som används för blockargument är (naturligtvis) lokala för blocket, men överskuggar tidigare definierade variabler utan att skriva över dem.
overshadowed = "sunlight"
["darkness"].each do |overshadowed|
p overshadowed
end
# darkness
# => ["darkness"]
p overshadowed
# "sunlight"
# => "sunlight"
Klassvariabler
Klassvariabler har ett klassbrett omfattning, de kan deklareras var som helst i klassen. En variabel kommer att betraktas som en klassvariabel när den är förinställd med @@
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"
Klassvariabler delas mellan relaterade klasser och kan skrivas över från en barnklass
class TRex < Dinosaur
@@classification = "Big teeth bird!"
end
TRex.classification
# => "Big teeth bird!"
Dinosaur.classification
# => "Big teeth bird!"
Detta beteende är oönskat större delen av tiden och kan kringgås med hjälp av instansvariabler på klassnivå.
Klassvariabler definierade i en modul kommer inte att skriva över deras inkluderande klasser klassvariabler:
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!"
Globala variabler
Globala variabler har ett globalt omfång och kan därför användas överallt. Deras omfattning beror inte på var de definieras. En variabel kommer att betraktas som global när den är förinställd med ett $
-tecken.
$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?"
Eftersom en global variabel kan definieras överallt och kommer att vara synlig överallt kommer en "odefinierad" global variabel att returnera noll istället för att ta upp ett fel.
p $undefined_var
# nil
# => nil
Även om globala variabler är enkla att använda, är användningen starkt avskräckt till förmån för konstanter.
Instansvariabler
Instansvariabler har ett objektbrett omfattning, de kan deklareras var som helst i objektet, men en instansvariabel som deklareras på klassnivå kommer bara att vara synlig i klassobjektet. En variabel kommer att betraktas som en instansvariabel när den är förinställd med @
. Instansvariabler används för att ställa in och få ett objektattribut och kommer att returnera noll om det inte är definierat.
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"
Den instansvariabel som deklarerats på klassnivå kan inte nås på objektnivå:
dino_1.try_to_speak
# => nil
Men vi använde instansvariabeln @base_sound
att instansera ljudet när inget ljud skickas till den nya metoden:
dino_1.speak
# => "rawwr"
Instansvariabler kan deklareras var som helst i objektet, även i ett block:
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
Instansvariabler delas inte mellan instanser av samma klass
dino_2.sound_length
# => nil
Detta kan användas för att skapa klassnivåvariabler, som inte kommer att skrivas över av en barnklass, eftersom klasser också är objekt i 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"