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

Sam*_*mes 0 ruby global global-variables

我已经阅读关于全局变量的C2Wiki,我有三个关于它们的问题(在这篇文章的底部).主要问题是:如果全局变量如此糟糕,为什么Ruby会有它们?

此外,我注意到一些关于Ruby中全局变量的有趣行为,这使得它们与常规全局级常量的工作方式不同.

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>'
Run Code Online (Sandbox Code Playgroud)

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>> 
Run Code Online (Sandbox Code Playgroud)

我的问题是:

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

eik*_*iko 5

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

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

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

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

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


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

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

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


至于为什么全局常量未初始化和全局变量nil,这实际上与全局变量无关.Ruby会自动将所有变量初始化为nil.您可以使用实例变量(例如@foo或)轻松查看此内容@@foo.在几乎所有情况下,未定义的局部变量都会抛出一个NameError因为ruby无法判断它是变量还是方法.但在奇怪的情况下,它们也被初始化为nil:

puts foo # => NameError: undefined local variable or method 'foo'
foo = 42 if false
puts foo # => nil

puts bar # => NameError
bar = bar
puts bar # => nil
Run Code Online (Sandbox Code Playgroud)

Ruby中有意识的设计选择是自动初始化常量.因为根据定义,常量是初始化一次然后从未改变的东西,它会使常量的定义首先打破nil,然后在代码中稍后使用不同的值.


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