Ruby Language
Область видимости и видимость
Поиск…
Синтаксис
- $ global_variable
- @@ class_variable
- @instance_variable
- local_variable
замечания
Переменные класса разделяются в иерархии классов. Это может привести к неожиданному поведению.
class A
@@variable = :x
def self.variable
@@variable
end
end
class B < A
@@variable = :y
end
A.variable # :y
Классы - это объекты, поэтому переменные экземпляра могут использоваться для предоставления состояния, специфичного для каждого класса.
class A
@variable = :x
def self.variable
@variable
end
end
class B < A
@variable = :y
end
A.variable # :x
Локальные переменные
Локальные переменные (в отличие от других классов переменных) не имеют префикса
local_variable = "local"
p local_variable
# => local
Его объем зависит от того, где он был объявлен, он не может использоваться вне области «контейнеры объявлений». Например, если локальная переменная объявлена в методе, ее можно использовать только внутри этого метода.
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'
Конечно, локальные переменные не ограничиваются методами, поскольку вы можете сказать, что, как только вы объявляете переменную внутри do ... end
block или завернуты в фигурные скобки {}
она будет локальной и скопирована в блок, в котором он был объявлен.
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'
Однако локальные переменные, объявленные в блоках if
или case
могут использоваться в родительской области:
if true
usable = "yay"
end
p usable
# yay
# => "yay"
Хотя локальные переменные не могут использоваться вне блока объявления, они будут переданы в блоки:
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"]
Но не для определения метода / класса / модуля
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'
Переменные, используемые для аргументов блока (конечно), являются локальными для блока, но будут затенять ранее определенные переменные, не перезаписывая их.
overshadowed = "sunlight"
["darkness"].each do |overshadowed|
p overshadowed
end
# darkness
# => ["darkness"]
p overshadowed
# "sunlight"
# => "sunlight"
Переменные класса
Переменные класса имеют классный охват, они могут быть объявлены в любом месте класса. Переменная будет считаться переменной класса, если префикс с @@
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"
Переменные класса разделяются между связанными классами и могут быть перезаписаны из дочернего класса
class TRex < Dinosaur
@@classification = "Big teeth bird!"
end
TRex.classification
# => "Big teeth bird!"
Dinosaur.classification
# => "Big teeth bird!"
Это поведение нежелательно в большинстве случаев и может быть обойдено с использованием переменных экземпляра класса.
Переменные класса, определенные внутри модуля, не будут перезаписывать их включенные переменные класса классов:
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!"
Глобальные переменные
Глобальные переменные имеют глобальный масштаб и, следовательно, могут использоваться повсеместно. Их объем не зависит от того, где они определены. Переменная будет считаться глобальной, с префиксом знака $
.
$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?"
Поскольку глобальная переменная может быть определена везде и будет видна повсюду, вызов глобальной неопределенной глобальной переменной будет возвращать нуль вместо повышения ошибки.
p $undefined_var
# nil
# => nil
Хотя глобальные переменные легко использовать, его использование сильно не рекомендуется в пользу констант.
Переменные экземпляра
Переменные экземпляра имеют объектную широкую область, они могут быть объявлены в любом месте объекта, однако переменная экземпляра, объявленная на уровне класса, будет видна только в объекте класса. Переменная будет считаться переменной экземпляра, если префикс с @
. Переменные экземпляра используются для установки и получения атрибутов объектов и возвращают нуль, если они не определены.
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"
Переменная экземпляра, объявленная на уровне класса, не может быть доступна на уровне объекта:
dino_1.try_to_speak
# => nil
Однако мы использовали переменную экземпляра @base_sound
для создания экземпляра звука, когда звук не передается новому методу:
dino_1.speak
# => "rawwr"
Переменные экземпляра могут быть объявлены в любом месте объекта, даже внутри блока:
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
Переменные экземпляра не разделяются между экземплярами одного и того же класса
dino_2.sound_length
# => nil
Это можно использовать для создания переменных уровня класса, которые не будут перезаписаны дочерним классом, поскольку классы также являются объектами в 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"