在Ruby中,为什么启动irb后,foo.nil?说未定义错误,@foo.nil?给出“true”,并且@@wah.nil?又报错了?

发布于 2024-09-29 06:05:15 字数 374 浏览 0 评论 0原文

Ruby 1.8.7 和 1.9.2 中相同:

$ irb

ruby-1.8.7-p302 > foo.nil?
NameError: undefined local variable or method `foo' for #<Object:0x3794c>
    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

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

Same in Ruby 1.8.7 and 1.9.2:

$ irb

ruby-1.8.7-p302 > foo.nil?
NameError: undefined local variable or method `foo' for #<Object:0x3794c>
    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

why the instance variable treated differently than a local and class variable?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

玩物 2024-10-06 06:05:15

在 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

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

if false
  fnord = 42
end
fnord              #=> nil

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

事实上并非如此。它的处理方式与局部变量相同。类层次结构变量是行为不同的变量,局部变量、实例变量和全局变量的行为都是相同的。

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

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

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

In Ruby, most uninitialized or even non-existing variables evaluate to nil. This is true for local variables, instance variables and global variables:

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

It is, however, not true for class hierarchy variables and constants:

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

defined? QUUX      #=> nil
QUUX
# NameError: uninitialized constant Object::QUUX

This is a red herring:

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

The reason why you get an error here is not that unitialized local variables don't evaluate to nil, it is that fnord is ambiguous: it could be either an argument-less message send to the default receiver (i.e. equivalent to self.fnord()) or an access to the local variable fnord.

In order to disambiguate that, you need to add a receiver or an argument list (even if empty) to tell Ruby that it is a message send:

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

or make sure that the parser (not the evaluator) parses (not executes) an assignment before the usage, to tell Ruby that it is a local variable:

if false
  fnord = 42
end
fnord              #=> nil

why the instance variable treated differently than a local and class variable?

It's not, actually. It's treated the same as a local variable. The class hierarchy variable is the one that behaves differently, local variables, instance variables and global variables all behave the same.

is there other reasons … can't class variables behave like that too?

I don't know. For instance variables it is very convenient, since unlike in Java, for example, where instance variables are declared in the class definition und thus always exist for every instance of the class, in Ruby, instance variables aren't declared anywhere. They just magically spring into existence, as soon as they are assigned. Since instance variables aren't necessarily guaranteed to exist, writing methods that use instance variables would be a pain if they threw exceptions.

Why class hierarchy variables are different, I have no idea. Maybe it's because nobody uses them anyway, or because they generally tend to be initialized in the class body and simply aren't accessed when they are not initialized.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文