Как ссылаться на глобальные переменные и переменные класса?
Я новичок в программировании. Прямо сейчас я изучаю Руби. Насколько я понимаю, глобальные переменные определены в глобальном пространстве имен (поэтому вне любых классов или функций). Я читаю что-то, и он говорит, что глобальные переменные имеют перед ними знак $
. Что это значит? Означает ли это, когда я определяю функцию или класс и хочу ссылаться на мою глобальную переменную (скажем, это edmund = 123
), мне пришлось бы ссылаться на нее следующим образом: $edmund
?
так:
edmund = 123
def my_function()
456 + $edmund
end
Также есть переменные класса (те, которые начинаются с @@
), такие как переменные экземпляра (@
), где вы можете получить к ним доступ, вызывая их через Class.classvariable
? Какова их цель?
Ответы
Ответ 1
Глобальная область действия - это область охвата всей программы. Глобальную область охвата используют глобальные переменные, которые можно распознать по их первоначальному знаку доллара ($). Theyre доступный везде и создание ваших собственных глобальных переменных может быть соблазнительным, особенно для начинающих программистов. Но они не всегда являются хорошей идеей.
$gvar = "I'm a global!"
class C
def examine_global
puts $gvar
end
end
c = C.new
c.examine_global # I'm a global!
Переменные класса начинаются с двух знаков: @@var. Несмотря на их имя, переменные класса arent class scoped. Скорее, их иерархия классов. В своей простейшей идее переменной класса заключается в том, что она обеспечивает механизм хранения, который разделяет между классом и экземплярами этого класса и не видимый для каких-либо других объектов.
class Parent
@@value = 100
end
class Child < Parent
@@value = 200
end
class Parent
puts @@value
end
То, что печатается, - 200. Класс Child является подклассом Parent, а это означает, что Parent и Child совместно используют одни и те же переменные класса - не разные переменные класса с одинаковыми именами, а одни и те же фактические переменные. Когда вы назначаете значение @@в Child, вы устанавливаете одну и только переменную значения @@, которая будет использоваться по всей иерархии,
то есть родителем и ребенком и любыми другими классами потомков любого из них.
И дать кредит там, где это необходимо - это объяснение от "The Well Grounded Rubyist" Дэвида Блэка, одного из лучших ресурсов, чтобы узнать о Ruby.
Ответ 2
Отличный вопрос. К сожалению, вы просто спрыгнули вниз по кроличьей норе, но это тот, который вы должны провалить в конце концов в рубине, чтобы начать понимать настоящие тонкости.
Для вашего первого вопроса, относящегося к глобальным переменным $
-prefixed. Они действительно глобальны:
def mk_foo() $foo ||= "foo"; end
$foo # => nil
mk_foo # => "foo"
$foo # => "foo"
mk_foo.object_id # => 70299647799620
$foo.object_id # => 70299647799620
Как вы можете видеть, когда $foo
определяется в методе mk_foo
, он определяется в глобальном пространстве, и вы можете получить к нему доступ в любом месте:
class CanSeeFoo
def see_foo() $foo; end
end
CanSeeFoo.new.can_see_foo
# => "foo"
CanSeeFoo.new.can_see_foo.object_id
# => 70299647799620
Что касается вопроса переменной класса, то здесь начинается кроличья дыра. Во-первых, вы правы, что переменные @@
-prefixed называются "переменными класса", а переменные @
-prefixed называются "переменными экземпляра".
Переменные класса являются статичными во всех подклассах (на всех подэлементах дерева наследования) определяющего класса. Здесь подразумевается, что если какой-либо подкласс изменяет переменную класса, он будет изменяться во всех связанных подклассах и до определяющего класса.
class A; end
class B < A; @@foo = "foo"; end
B.class_variable_get(:@@foo) # => "foo"
A.class_variable_get(:@@foo)
# => raises NameError "uninitialized class variable @@foo in A"
class C < B; end
C.class_variable_get(:@@foo) # => "foo"
class D < C
def self.change_foo(); @@foo = "bar"; end
def change_foo(); @@foo = "baz"; end
end
D.class_variable_get(:@@foo) # => "foo"
class E < D; end
E.class_variable_get(:@@foo) # => "foo"
D.change_foo # => "bar"
D.class_variable_get(:@@foo) # => "bar"
E.class_variable_get(:@@foo) # => "bar"
C.class_variable_get(:@@foo) # => "bar"
B.class_variable_get(:@@foo) # => "bar"
D.new.change_foo # => "baz"
D.class_variable_get(:@@foo) # => "baz"
E.class_variable_get(:@@foo) # => "baz"
C.class_variable_get(:@@foo) # => "baz"
B.class_variable_get(:@@foo) # => "baz"
A.class_variable_get(:@@foo)
# => raises NameError "uninitialized class variable @@foo in A"
Как для доступа к переменным класса и экземпляра, ни один из них недоступен без использования #instance_variable_get
или ::class_variable_get
до тех пор, пока не будет определен аксессор. В настоящее время у Ruby есть только методы определения аксессуаров для переменных экземпляра, но достаточно просто определить соответствующие методы для переменных класса:
class A
@@foo = "foo"
# the second argument `true` adds the writer method `#bar=`
attr :bar, true
def self.foo(); @@foo; end
def self.foo=(v); @@foo = v; end
def initialize()
@bar = "bar"
end
end
class B < A; end
A.foo # => "foo"
B.foo = "foobar"
A.foo # => "foobar"
B.foo # => "foobar"
a = A.new
a.bar # => "bar"
a.bar = "baz"
a.bar # => "baz"
a.foo
# => raises NoMethodError: undefined method `foo' for #<A:0x ...
Здесь вы можете увидеть методы доступа к атрибутам в документах ruby core: http://www.ruby-doc.org/core-1.9.3/Module.html#method-i-attr. Кроме того, ActiveSupport (http://rubygems.org/gems/activesupport) имеет методы "cattr
" для определения доступа к переменной класса http://api.rubyonrails.org/v3.2.5/classes/Class.html#method-i-cattr_accessor.
Это простой материал. Следующим шагом является понимание "singleton class", также известного как "eigenclass" или "metaclass" (Wikipedia: Metaclass) (помните, что все в ruby - объект, включая конструкции класса и модуля). Здесь я укажу вам на отличный пост от Yehuda Katz: Метапрограммирование в Ruby: все о себе и еще один вопрос: < класс href= "/questions/12412/class-self-idiom-in-ruby" > < self idiom в Ruby.
В качестве предварительного просмотра: Singleton-класс (не путать с шаблоном проектирования singleton) позволяет вам получить доступ к методам и данным экземпляра для определенного класса или модуля. Для некоторых связанных документов см. Основные документы: http://www.ruby-doc.org/core-1.9.3/Object.html#method-i-singleton_class
class A; end
class B < A;
class << self
def foo() @foo end
def foo=(v) @foo = v; end
end
end
B.foo = "foo"
class C < B; end
A.foo
# => raises NoMethodError: undefined method `foo' for A:Class
B.foo # => "foo"
C.foo # => nil
B.foo = "baz"
B.foo # => "baz"
C.foo # => nil
C.foo = "foo"
C.foo # => "foo"
B.foo # => "baz"
Наконец, не забудьте использовать Документы Ruby-Core. Наиболее полезными для понимания вышесказанного являются:
Ответ 3
Знак доллара является частью имени переменной, поэтому его нужно объявить следующим образом:
$edmund = 123
Это то же самое для переменных экземпляра и класса: их имена начинаются с @
или @@
.
Ответ 4
Ознакомьтесь с этими статьями:
http://www.rubyist.net/~slagell/ruby/globalvars.html
и
Как вы используете глобальные переменные или константные значения в Ruby?