关于ruby:如何引用全局变量和类变量?

How to reference global variables and class variables?

我是编程新手。 现在我正在研究Ruby。 据我所知,全局变量是在全局命名空间中定义的(所以在任何类或函数之外)。 我正在读一些东西,它说全局变量在它们之前有一个$符号。 那是什么意思? 这是否意味着当我定义一个函数或类并想要引用我的全局变量(假设它是edmund = 123)时,我必须像这样引用它:$edmund

所以:

1
2
3
4
edmund = 123
def my_function()
  456 + $edmund
end

也是类变量(以@@开头的那些),例如实例变量(@),你可以通过Class.classvariable调用它们来访问它们吗? 他们的目的是什么?


全球范围是涵盖整个计划的范围。全局变量享有全局变量,可通过其初始美元符号($)字符识别。它们随处可用,创建自己的全局变量可能很诱人,特别是初学程序员。但他们并不总是一个好主意。

1
2
3
4
5
6
7
8
9
$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。尽管它们的名称,类变量不是类作用域。相反,它们是类层次结构范围。最简单的说,类变量背后的想法是它提供了一个存储机制,该机制在类的类和实例之间共享,并且对任何其他对象都不可见。

1
2
3
4
5
6
7
8
9
10
11
class Parent
    @@value = 100
end

class Child < Parent
    @@value = 200
end

class Parent
    puts @@value
end

打印的内容是200. Child类是Parent的子类,这意味着Parent和Child共享相同的类变量 - 不是具有相同名称的不同类变量,而是相同的实际变量。当您在Child中分配给@@值时,您将设置在整个层次结构中共享的唯一@@值变量 -
也就是说,由Parent和Child以及其中任何一个的任何其他后代类。

并给予应有的信誉 - 这个解释来自David A Black的"The Well Grounded Rubyist",这是了解Ruby的最佳资源之一。


好问题。不幸的是,你只是跳下了一个兔子洞,但是你必须最终落入红宝石才能开始理解真正错综复杂的洞穴。

关于第一个问题,关于$ - 前缀全局变量。他们是真正的全球:

1
2
3
4
5
6
7
def mk_foo() $foo ||="foo"; end

$foo                # => nil
mk_foo              # =>"foo"
$foo                # =>"foo"
mk_foo.object_id    # => 70299647799620
$foo.object_id      # => 70299647799620

如您所见,当$foomk_foo方法中定义时,它在全局空间中定义,您可以在任何地方访问它:

1
2
3
4
5
6
7
class CanSeeFoo
  def see_foo() $foo; end
end
CanSeeFoo.new.can_see_foo
# =>"foo"
CanSeeFoo.new.can_see_foo.object_id
# => 70299647799620

至于类变量问题,这就是兔子洞开始的地方。首先,你是正确的,@@ - 前缀变量被称为"类变量",@ - 前缀变量被称为"实例变量"。

类变量在定义类的所有子类(在继承树的所有子级别)都是静态的。这里的含义是,如果任何子类更改了类变量,它将在所有相关的子类中更改,直到定义的类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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只有在实例变量上定义访问器的方法,但它足够简单,可以为类变量定义适当的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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核心文档中看到属性访问器方法: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。

这是简单的事情。下一步是理解"单例类",也称为"特征类"或"元类"(维基百科:元类)(请记住,ruby中的所有内容都是Object,包括类和模块结构)。在这里,我将向您指出Yehuda Katz的一篇优秀文章:Ruby中的元编程:它是关于自我的全部,以及另一个Stack Overflow问题:类<< Ruby中的自我成语。

作为预览:单例类(不要与单例设计模式混淆)允许您访问特定类或模块的方法和实例数据。有关相关文档,请参阅核心文档:http://www.ruby-doc.org/core-1.9.3/Object.html#method-i-singleton_class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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文档。对于理解上述内容最有用的是:

  • http://www.ruby-doc.org/core-1.9.3/Object.html
  • http://www.ruby-doc.org/core-1.9.3/Module.html
  • http://www.ruby-doc.org/core-1.9.3/Class.html


美元符号是变量名称的一部分,因此必须如下声明:

1
$edmund = 123

这与实例和类变量相同:它们的名称以@@@开头。


看看这些文章:

http://www.rubyist.net/~slagell/ruby/globalvars.html

你如何在Ruby中使用全局变量或常量值?