Подтвердить что ты не робот

Как ссылаться на глобальные переменные и переменные класса?

Я новичок в программировании. Прямо сейчас я изучаю Руби. Насколько я понимаю, глобальные переменные определены в глобальном пространстве имен (поэтому вне любых классов или функций). Я читаю что-то, и он говорит, что глобальные переменные имеют перед ними знак $. Что это значит? Означает ли это, когда я определяю функцию или класс и хочу ссылаться на мою глобальную переменную (скажем, это edmund = 123), мне пришлось бы ссылаться на нее следующим образом: $edmund?

так:

edmund = 123
def my_function()
  456 + $edmund
end

Также есть переменные класса (те, которые начинаются с @@), такие как переменные экземпляра (@), где вы можете получить к ним доступ, вызывая их через Class.classvariable? Какова их цель?

4b9b3361

Ответ 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

Это то же самое для переменных экземпляра и класса: их имена начинаются с @ или @@.