为什么Ruby中存在全局变量?

时间:2017-05-26 13:47:04

标签: ruby global-variables global

我在全球变量上看过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初始化时定义了$stdoutSTDOUT。您可以重新定义$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>> 

我的问题是:

  • 如果全局变量如此糟糕,为什么Ruby会拥有它们?
  • 为什么引用未定义的全局变量会返回nil而不是NameError?这个选择是故意的吗?为什么?
  • 在一个程序中有两个几乎同名的STDOUT版本有危险吗? (我假设还有其他全局定义的对象也适用于此)

1 个答案:

答案 0 :(得分:5)

全局变量也不错。他们不是邪恶的。它们令人难以置信,非常强大。这就是你不应该使用它们的原因。

全局变量是全局变量 - 可以在代码中的任何位置访问和修改它们。单个全局变量有可能影响所有类,所有函数,每个库的所有类和函数或加载到项目中的依赖项,所有类和将您的项目作为依赖项加载的每个项目的功能,以及加载这些项目的项目,等等,永远和永远,剩下的时间。

第二个人开始使用全局变量感觉很舒服,命名空间变得非常混乱,我们左右冲突,编程语言本身的稳定性受到威胁。这就是为什么强调和反复使用全局变量的原因。

但全球变量并不坏。它们就像标有“仅用于紧急车辆”的高速公路车道,或者像玻璃后面的那些斧头标记为“紧急情况下的破碎玻璃”。

完全有可能在某个时候,在遥远的未来,你会有一个非常不寻常的情况,值得使用一个全局变量。但那一天不是今天。它可能不是明天,也可能是一个月后,也可能是一年之后。日常生活,每日代码 - 它并没有要求全球变量的肆无忌惮的力量。

$stdout是一个很好的例子,说明为什么全局变量有时很重要。 $stdout是ruby中的默认流 - 如果没有指定其他流,则会打印事物。 $stdout应该可以从每个类和每个库中的每个函数访问,因为它像一个巨大的漏斗,将所有输出铲到一个位置。全世界都知道并同意$stdout存在于红宝石中,其用途已被充分记录,因此其功能得到了很好的管理。

这不应与STDOUT混淆,$stdout = STDOUT是一个常量,表示在ruby及其父程序(通常是终端)之间设置流的实际管道。默认情况下为$stdout,但$stdout可以更改为任何内容。如果希望程序打印到文件,可以将nil更改为文件流。

我不认为这个名字的选择会让经验丰富的红宝石感到困惑。设计一个变量进行修改,并将常量设计为常量。 $ stdout和STDOUT之间的区别在于可以修改前者以更改程序的标准输出位置,后者是常量,始终指向stdout流。资本化使世界变得不同,并传达了截然不同的含义。

至于为什么全局常量未初始化且全局变量为nil,这实际上与全局变量无关。 Ruby会自动将所有变量初始化为@foo。您可以使用@@fooNameError等实例变量轻松查看此内容。在几乎所有情况下,未定义的局部变量都会抛出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) ,然后在代码中稍后将其打开。

我还应该提到全局常量被认为是可接受的,即使是那些将全局变量称为坏的人也是如此。区别在于常量只能分配一次,如果再次分配,通常会发出警告或错误。这可以保护程序员免受冲突的全局常量可能导致问题的情况的影响。