在Ruby中,为什么在启动irb之后,foo.nil? 说未定义的错误,@ foo.nil? 给出“真实”和@@ wah.nil? 再次出错?

在Ruby 1.8.7和1.9.2中也是如此:

$ irb ruby-1.8.7-p302 > foo.nil? NameError: undefined local variable or method `foo' for # from (irb):1 ruby-1.8.7-p302 > @bar.nil? => true ruby-1.8.7-p302 > @@wah.nil? NameError: uninitialized class variable @@wah in Object from (irb):3 

为什么实例变量的处理方式与局部变量和类变量不同?

在Ruby中,大多数未初始化或甚至不存在的变量评估为nil 。 对于局部变量,实例变量和全局变量都是如此:

 defined? foo #=> nil local_variables #=> [] if false foo = 42 end defined? foo #=> 'local-variable' local_variables #=> [:foo] foo #=> nil foo.nil? #=> true defined? @bar #=> nil instance_variables #=> [] @bar #=> nil @bar.nil? #=> true # warning: instance variable @bar not initialized defined? $baz #=> nil $baz #=> nil # warning: global variable `$baz' not initialized $baz.nil? #=> true # warning: global variable `$baz' not initialized 

但是,类层次结构变量和常量不是这样的:

 defined? @@wah #=> nil @@wah # NameError: uninitialized class variable @@wah in Object defined? QUUX #=> nil QUUX # NameError: uninitialized constant Object::QUUX 

这是一个红鲱鱼:

 defined? fnord #=> nil local_variables #=> [] fnord # NameError: undefined local variable or method `fnord' for main:Object 

你在这里得到一个错误的原因并不是单位化的局部变量不能计算为nil ,而是fnord是不明确的:它可以是一个无参数的消息发送到默认的接收者(即相当于self.fnord()访问本地变量fnord

为了消除歧义,你需要添加一个接收器或参数列表(即使是空的)来告诉Ruby它是一个消息发送:

 self.fnord # NoMethodError: undefined method `fnord' for main:Object fnord() # NoMethodError: undefined method `fnord' for main:Object 

或者确保解析器而不是求值程序)在使用之前解析( 执行)赋值,告诉Ruby它是一个局部变量:

 if false fnord = 42 end fnord #=> nil 

为什么实例变量的处理方式与局部变量和类变量不同?

实际上并非如此。 它被视为局部变量。 类层次结构变量是行为不同的变量,局部变量,实例变量和全局变量的行为都相同。

还有其他原因……类变量的行为也不能吗?

我不知道。 例如,变量非常方便,因为与Java不同,例如,在类定义中声明实例变量,因此对于类的每个实例始终存在,在Ruby中,实例变量不会在任何地方声明。 一旦他们被分配,他们就会神奇地存在。 由于实例变量不一定能保证存在,因此编写使用实例变量的方法如果抛出exception就会很痛苦。

为什么类层次结构变量不同,我不知道。 也许这是因为无论如何都没有人使用它们,或者因为它们通常倾向于在类体中初始化,并且在未初始化时根本不被访问。