我在全球变量上看过C2Wiki,我对它们有三个问题(在这篇文章的底部)。主要问题是:如果全局变量如此糟糕,为什么Ruby会有它们?
另外,我注意到Ruby中有关Global全局变量的一些有趣行为,导致它们与常规全局级常量的工作方式不同。
1。引用未定义的全局变量返回nil
。引用未定义的全局常量将返回NameError
:
2.2.3 :001 > $THING
=> nil
2.2.3 :002 > THING
NameError: uninitialized constant THING
from (irb):2
from /Users/makerslaptop82/.rvm/rubies/ruby-2.2.3/bin/irb:15:in `<main>'
2。 irb
初始化时定义了$stdout
和STDOUT
。您可以重新定义$stdout
,这不会影响STDOUT
:
2.2.3 :001 > $stdout
=> #<IO:<STDOUT>>
2.2.3 :002 > STDOUT
=> #<IO:<STDOUT>>
2.2.3 :003 > $stdout = IO.new(6)
=> #<IO:fd 6>
2.2.3 :004 > $stdout
=> #<IO:fd 6>
2.2.3 :005 > STDOUT
=> #<IO:<STDOUT>>
我的问题是:
nil
而不是NameError
?这个选择是故意的吗?为什么?答案 0 :(得分:5)
全局变量也不错。他们不是邪恶的。它们令人难以置信,非常强大。这就是你不应该使用它们的原因。
全局变量是全局变量 - 可以在代码中的任何位置访问和修改它们。单个全局变量有可能影响所有类,所有函数,每个库的所有类和函数或加载到项目中的依赖项,和所有类和将您的项目作为依赖项加载的每个项目的功能,以及加载这些项目的项目,等等,永远和永远,剩下的时间。
第二个人开始使用全局变量感觉很舒服,命名空间变得非常混乱,我们左右冲突,编程语言本身的稳定性受到威胁。这就是为什么强调和反复使用全局变量的原因。
但全球变量并不坏。它们就像标有“仅用于紧急车辆”的高速公路车道,或者像玻璃后面的那些斧头标记为“紧急情况下的破碎玻璃”。
完全有可能在某个时候,在遥远的未来,你会有一个非常不寻常的情况,值得使用一个全局变量。但那一天不是今天。它可能不是明天,也可能是一个月后,也可能是一年之后。日常生活,每日代码 - 它并没有要求全球变量的肆无忌惮的力量。
$stdout
是一个很好的例子,说明为什么全局变量有时很重要。 $stdout
是ruby中的默认流 - 如果没有指定其他流,则会打印事物。 $stdout
应该可以从每个类和每个库中的每个函数访问,因为它像一个巨大的漏斗,将所有输出铲到一个位置。全世界都知道并同意$stdout
存在于红宝石中,其用途已被充分记录,因此其功能得到了很好的管理。
这不应与STDOUT
混淆,$stdout = STDOUT
是一个常量,表示在ruby及其父程序(通常是终端)之间设置流的实际管道。默认情况下为$stdout
,但$stdout
可以更改为任何内容。如果希望程序打印到文件,可以将nil
更改为文件流。
我不认为这个名字的选择会让经验丰富的红宝石感到困惑。设计一个变量进行修改,并将常量设计为常量。 $ stdout和STDOUT之间的区别在于可以修改前者以更改程序的标准输出位置,后者是常量,始终指向stdout流。资本化使世界变得不同,并传达了截然不同的含义。
至于为什么全局常量未初始化且全局变量为nil
,这实际上与全局变量无关。 Ruby会自动将所有变量初始化为@foo
。您可以使用@@foo
或NameError
等实例变量轻松查看此内容。在几乎所有情况下,未定义的局部变量都会抛出nil
,因为ruby无法判断它是变量还是方法。但在奇怪的情况下,它们也被初始化为puts foo # => NameError: undefined local variable or method 'foo'
foo = 42 if false
puts foo # => nil
puts bar # => NameError
bar = bar
puts bar # => nil
:
nil
在Ruby not 中有意识地设计选择自动初始化常量。因为根据定义,常量是初始化一次然后从未改变的东西,它会使常量的定义首先打破(?:^|\s)if(?:\s)
,然后在代码中稍后将其打开。
我还应该提到全局常量被认为是可接受的,即使是那些将全局变量称为坏的人也是如此。区别在于常量只能分配一次,如果再次分配,通常会发出警告或错误。这可以保护程序员免受冲突的全局常量可能导致问题的情况的影响。