如何引用全局变量和类变量?

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

所以:

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

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

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

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

 class Parent @@value = 100 end class Child < Parent @@value = 200 end class Parent puts @@value end 

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


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

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

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

 def mk_foo() $foo ||= "foo"; end $foo # => nil mk_foo # => "foo" $foo # => "foo" mk_foo.object_id # => 70299647799620 $foo.object_id # => 70299647799620 

如您所见,当在mk_foo方法中定义$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变量被称为“实例变量”。

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

 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 # 

您可以在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

 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文档 。 对于理解上述内容最有用的是:

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

 $edmund = 123 

对于实例和类变量,这是相同的事情:它们的名称以@@@开头。

看看这些文章:

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

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