当文件被 Ruby 解析时,为什么常量不像局部变量那样初始化? [英] Why are constants not initialized like local variables when the file is parsed by Ruby?

查看:33
本文介绍了当文件被 Ruby 解析时,为什么常量不像局部变量那样初始化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Ruby 中,我知道我可以做这样的事情:

In Ruby, I am aware that I can do things like this:

if false
  var = "Hello"
end

puts var

应用程序不会崩溃,并且 var 只是设置为 nil.我了解到这是由于 Ruby 解析器的工作方式造成的.

The application doesn't crash, and var is simply set to nil. I've read that this happens due to the way the Ruby parser works.

为什么同样的方法不适用于常量?

if false
  MY_CONST = "Hello"
end

puts MY_CONST
=> uninitialized constant MY_CONST (NameError)

推荐答案

TL;DR

局部变量在解析器遇到时被定义,而常量不是.但是,在解释器评估时必须定义两者以避免 NameError.

TL;DR

Local variables are defined when encountered by the parser, while constants are not. However, both must be defined when evaluated by the interpreter to avoid NameError.

您的原始代码实际上并未为局部变量或常量赋值.在这两种情况下,if false 永远不会为真,因此永远不会执行赋值语句.但是,解析器对未定义的变量和常量的处理方式不同.

Your original code doesn't actually assign a value to either the local variable or the constant. In both cases, if false is never truthy, so the assigment statements are never executed. Undefined variables and constants are handled differently by the parser, though.

除了范围问题,局部变量解析器遇到赋值时创建,而不仅仅是在赋值发生时.所以,即使:

Scoping issues aside, local variables are created when the parser encounters the assignment, not just when the assignment occurs. So, even though:

if false
  var = "Hello"
end

从不执行赋值,它仍然将局部变量初始化为nil.

never executes the assignment, it still initializes the local variable to nil.

另一方面,常量的处理方式不同.在当前命名空间中不可用的未知常量(实际上是以大写字母开头的任何内容)将引发 NameError.

Constants, on the other hand, are treated differently. An unknown constant (really, anything that starts with an uppercase letter) that isn't available within the current namespace will raise a NameError.

在新的 irb 会话中,这两个都会引发 NameError,但异常消息略有不同:

In a fresh irb session, both of these will raise NameError, but with slightly different exception messages:

puts var
#=> NameError (undefined local variable or method `var' for main:Object)

puts MY_CONST
#=> NameError (uninitialized constant MY_CONST)

但是,如果您更改分支逻辑,以便解释器评估带有未定义变量的表达式,您也会得到 NameError:

However, if you change your branch logic so that an expression with an undefined variable is evaluated by the interpreter, you'll also get NameError:

if baz
  puts true
end

#=> NameError (undefined local variable or method `baz' for main:Object)

另一种检查行为的方法

启动新的 irb 会话.然后:

Another Way to Examine the Behavior

Fire up a fresh irb session. Then:

irb(main):001:0> defined? var
#=> nil
irb(main):002:0> if false then var = 1 end
#=> nil
irb(main):003:0> defined? var
#=> "local-variable"

您可以看到 var 在解析器遇到时已定义并设置为 nil,即使从未计算赋值表达式.但是,常量不会自动激活:

You can see that var is both defined and set to nil when encountered by the parser, even though the assignment expression is never evaluated. The constant is not auto-vivified, though:

irb(main):004:0> defined? MY_CONST
#=> nil
irb(main):005:0> if false then MY_CONST = 1 end
#=> nil
irb(main):006:0> defined? MY_CONST
#=> nil
irb(main):007:0> MY_CONST
#=> NameError (uninitialized constant MY_CONST)

结论

虽然我猜这种行为与解析器和解释器之间的差异有关,也可能与用于变量/方法查找与常量查找的命名空间之间的差异有关,但我真的无法告诉您为什么 差异是必要的(如果确实如此),或者即使它在所有 Ruby 实现中都相同.这是各种 Ruby 引擎开发人员的问题,包括 Ruby 核心团队.

Conclusions

While I would guess this behavior has to do with differences between the parser and the interpreter, and perhaps between the namespaces used for variable/method lookup vs. constant lookup, I can't really tell you why the difference is necessary (if it really is), or even if it's the same across all Ruby implementations. That's a question for the various Ruby engine developers, including the Ruby Core Team.

实际上,当您尝试使用一个未定义的变量或常量时,总是会遇到 NameError 异常.因此,这种差异对现实世界的影响(如果有的话)很小.所有语言都有怪癖;这可能是其中之一,但除了人为的例子之外,很难看出这将如何导致实际问题.您的里程肯定会有所不同.

Pragmatically, though, you will always get a NameError exception when you attempt to use an undefined variable or constant. The real-world impact (if any) of this difference is therefore minimal. All languages have quirks; this may be one of them, but it's hard to see how this would cause practical problems outside of contrived examples. Your mileage may certainly vary.

这篇关于当文件被 Ruby 解析时,为什么常量不像局部变量那样初始化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆