我是编程新手.现在我正在研究Ruby.据我所知,全局变量是在全局命名空间中定义的(所以在任何类或函数之外).我正在读一些东西,它说全局变量$在他们面前有一个标志.那是什么意思?这是否意味着,当我定义一个函数或类,并要参考我的全局变量(让我们说这是edmund = 123)我将不得不像这样引用它:$edmund?
所以:
edmund = 123
def my_function()
456 + $edmund
end
Run Code Online (Sandbox Code Playgroud)
也是类变量(以那些开头的@@变量@),如实例变量(),您可以通过调用它们来访问它们Class.classvariable?他们的目的是什么?
sai*_*ala 45
全球范围是涵盖整个计划的范围.全局变量享有全局变量,可通过其初始美元符号($)字符识别.它们随处可用,创建自己的全局变量可能很诱人,特别是初学程序员.但他们并不总是一个好主意.
$gvar = "I'm a global!"
class C
def examine_global
puts $gvar
end
end
c = C.new
c.examine_global # I'm a global!
Run Code Online (Sandbox Code Playgroud)
类变量以两个符号开头:例如@@ var.尽管它们的名称,类变量不是类作用域.相反,它们是类层次结构范围.最简单的说,类变量背后的想法是它提供了一个存储机制,该机制在类的类和实例之间共享,并且对任何其他对象都不可见.
class Parent
@@value = 100
end
class Child < Parent
@@value = 200
end
class Parent
puts @@value
end
Run Code Online (Sandbox Code Playgroud)
打印的内容是200. Child类是Parent的子类,这意味着Parent和Child共享相同的类变量 - 不是具有相同名称的不同类变量,而是相同的实际变量.当您在Child中分配@@ value时,您将设置在整个层次结构中共享的唯一@@值变量 - 即父级和子级以及其中任何一个的任何其他后代类.
并给予应有的信誉 - 这个解释来自David A Black的"The Well Grounded Rubyist",这是了解Ruby的最佳资源之一.
好问题.不幸的是,你只是跳下了一个兔子洞,但是你必须最终落入红宝石才能开始理解真正错综复杂的洞穴.
关于第一个问题,关于$-prefixed全局变量.他们是真正的全球:
def mk_foo() $foo ||= "foo"; end
$foo # => nil
mk_foo # => "foo"
$foo # => "foo"
mk_foo.object_id # => 70299647799620
$foo.object_id # => 70299647799620
Run Code Online (Sandbox Code Playgroud)
如您所见,在$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
Run Code Online (Sandbox Code Playgroud)
至于类变量问题,这就是兔子洞开始的地方.首先,你是正确的 - @@前缀变量被称为"类变量",而@前缀变量被称为"实例变量".
类变量在定义类的所有子类(在继承树的所有子级别)都是静态的.这里的含义是,如果任何子类更改了类变量,它将在所有相关的子类中更改,直到定义的类.
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"
Run Code Online (Sandbox Code Playgroud)
至于访问类和实例变量,在没有使用#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 ...
Run Code Online (Sandbox Code Playgroud)
您可以在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"
Run Code Online (Sandbox Code Playgroud)
最后,请记住使用Ruby-Core文档.对于理解上述内容最有用的是:
美元符号是变量名称的一部分,因此必须这样声明:
$edmund = 123
Run Code Online (Sandbox Code Playgroud)
这对于实例变量和类变量来说是相同的:它们的名称以@or开头@@。
| 归档时间: |
|
| 查看次数: |
67715 次 |
| 最近记录: |