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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12112765/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 05:22:03  来源:igfitidea点击:

How to reference global variables and class variables?

ruby

提问by bigpotato

I'm new to programming. Right now I'm studying Ruby. To my understanding, global variables are defined in the global namespace (so outside of any classes or functions). I'm reading something and it says global variables have a $sign before them. What does that mean? Does it mean when I define a function or class and want to reference my global variable (let's say it is edmund = 123) I would have to reference it like this: $edmund?

我是编程新手。现在我正在学习Ruby。据我了解,全局变量是在全局命名空间中定义的(因此在任何类或函数之外)。我在读一些东西,它说全局变量$前面有一个标志。这意味着什么?这是否意味着当我定义一个函数或类并想要引用我的全局变量(假设它是edmund = 123)时,我必须像这样引用它:$edmund

so:

所以:

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

Also are class variables (the ones that begin with @@) like instance variables (@) where you can access them by calling them through Class.classvariable? What is their purpose?

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

回答by saihgala

Global scope is scope that covers the entire program. Global scope is enjoyed by global variables, which are recognizable by their initial dollar-sign ($) character. They're available everywhere and creating your own global variables can be tempting, especially for beginning programmers. But they're not always a good idea.

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

$gvar = "I'm a global!"
class C
    def examine_global
        puts $gvar
    end
end

c = C.new
c.examine_global # I'm a global!


Class variables begin with two at signs: @@var, for example. Despite their name, class variables aren't class scoped. Rather, they're class-hierarchy scoped. At its simplest, the idea behind a class variable is that it provides a storage mechanism that's shared between a class and instances of that class, and that's not visible to any other objects.

类变量以两个 at 符号开头:例如,@@var。尽管它们的名字,类变量不是类范围的。相反,它们是类层次结构范围的。简而言之,类变量背后的想法是它提供了一种在类和该类的实例之间共享的存储机制,并且对任何其他对象都不可见。

class Parent
    @@value = 100
end

class Child < Parent
    @@value = 200
end

class Parent
    puts @@value
end

What gets printed is 200. The Child class is a subclass of Parent, and that means Parent and Child share the same class variables—not different class variables with the same names, but the same actual variables. When you assign to @@value in Child, you're setting the one and only @@value variable that's shared throughout the hierarchy— that is, by Parent and Child and any other descendant classes of either of them.

打印出来的是 200。 Child 类是 Parent 的子类,这意味着 Parent 和 Child 共享相同的类变量——不是同名的不同类变量,而是相同的实际变量。当您在 Child 中分配 @@value 时,您正在设置一个且唯一的 @@value 变量,该变量在整个层次结构中共享 - 即由 Parent 和 Child 以及它们中任何一个的任何其他后代类共享。



And to give credit where its due - This explanation comes from "The Well Grounded Rubyist" by David A Black, one of the best resources to learn about Ruby.

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

回答by Travis Warlick

Excellent question. Unfortunately, you just jumped down a rabbit hole, but it's one that you have to fall through eventually in ruby to start understanding the real intricacies.

很好的问题。不幸的是,您刚刚跳下了一个兔子洞,但您最终必须在 ruby​​ 中通过这个洞才能开始了解真正的复杂性。

For your first question, regarding the $-prefixed global variables. They are truly global:

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

def mk_foo() $foo ||= "foo"; end

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

As you can see, when $foois defined within the mk_foomethod, it is defined in the global space, and you can access it anywhere:

可以看到,when$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

As for the class variable question, this is where the rabbit-hole begins. First, you are correct that @@-prefixed variables are referred to as "class variables" and @-prefixed variables are referred to as "instance variables".

至于类变量问题,这是兔子洞的开始。首先,您正确地认为@@-prefixed 变量被称为“类变量”,而@-prefixed 变量被称为“实例变量”。

Class variables are static across all subclasses (at all sub-levels of the inheritance tree) of the defining class. The implication here is that if any subclass changes the class variable, it will change in all related subclasses and up to the defining class.

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

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"

As for accessing class and instance variables, neither is accessible without the use of #instance_variable_getor ::class_variable_getuntil an accessor is defined. At present, ruby only has methods for defining accessors on instance variables, but it is simple enough to define the appropriate methods for the class variables:

至于访问类和实例变量,不使用#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 ...

You can see the attribute accessor methods here in the ruby core docs: http://www.ruby-doc.org/core-1.9.3/Module.html#method-i-attr. Also, ActiveSupport (http://rubygems.org/gems/activesupport) has "cattr" methods for defining class variable accessors http://api.rubyonrails.org/v3.2.5/classes/Class.html#method-i-cattr_accessor.

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

That's the simple stuff. The next step is understanding the "singleton class" also known as the "eigenclass" or "metaclass" (Wikipedia: Metaclass) (remember, everything in ruby is an Object, including the Class and Module constructs). Here I will point you to an excellent post by Yehuda Katz: Metaprogramming in Ruby: It's All About the Self, and another Stack Overflow question: class << self idiom in Ruby.

这就是简单的东西。下一步是理解“单例类”,也称为“特征类”或“元类”(维基百科:元类)(记住,ruby 中的一切都是对象,包括类和模块构造)。在这里,我将向您推荐 Yehuda Katz 的一篇优秀文章:Ruby 中的元编程:一切都是关于自我,以及另一个 Stack Overflow 问题:class << self idiom in Ruby

As a preview: The singleton class (not to be confused with the singleton design pattern) allows you to access methods and instance datafor a specific class or module. For some related documentation, see the core docs: http://www.ruby-doc.org/core-1.9.3/Object.html#method-i-singleton_class

作为预览:单例类(不要与单例设计模式混淆)允许您访问特定类或模块的方法和实例数据。有关一些相关文档,请参阅核心文档: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"

Lastly, remember to make use of the Ruby-Core docs. Most useful for understanding the above are:

最后,请记住使用Ruby-Core 文档。对理解上述内容最有用的是:

回答by philant

The dollar sign is part of the variable name, so it has to be declared like this:

美元符号是变量名的一部分,因此必须像这样声明:

$edmund = 123

This is the same things for the instance and class variables: their names begin with @or @@.

这对于实例变量和类变量来说是一样的:它们的名称以@or开头@@