未声明的实例变量默认为 nil?

Undeclared instance variables default to nil?

由于我的一些草率编码,我注意到未声明的实例变量似乎评估为 nil,而未声明的局部变量则没有。实例变量的这个默认空值是否是我可以利用的预期行为(比如有条件检查变量是否已设置为真)或者这只是一个应该单独留下的怪癖?

2.6.6 :001 > puts @test

 => nil 
2.6.6 :002 > puts test
Traceback (most recent call last):
        2: from (irb):2
        1: from (irb):2:in `test'
ArgumentError (wrong number of arguments (given 0, expected 2..3))

根据 Ruby 文档:

Instance variables of ruby do not need declaration. This implies a flexible structure of objects. In fact, each instance variable is dynamically appended to an object when it is first referenced.

https://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/instancevars.html

您还可以获得所有先前定义的实例变量的列表:

ClassName.instance_variables

a = ClassName.new 
a.instance_variables #specific to instance

tl;dr 是的,这在 Assignment.

中有记录

一个东西是否被定义,被定义成什么,可以用defined? keyword.

2.6.5 :003 > defined?(fnord)
 => nil 
2.6.5 :004 > fnord = 42
 => 42 
2.6.5 :005 > defined?(fnord)
 => "local-variable" 
2.6.5 :006 > defined?($fnord)
 => nil 
2.6.5 :007 > $fnord = 42
 => 42 
2.6.5 :008 > defined?($fnord)
 => "global-variable" 
2.6.5 :009 > defined?(@fnord)
 => nil 
2.6.5 :010 > @fnord = 42
 => 42 
2.6.5 :011 > defined?(@fnord)
 => "instance-variable" 
2.6.5 :012 > defined?(FNORD)
 => nil 
2.6.5 :013 > FNORD = 42
 => 42 
2.6.5 :014 > defined?(FNORD)
 => "constant" 

这对调试很有用,但我不鼓励在应用程序代码中“利用”它。


首先,让我们澄清一下您的示例。 testmain的一个方法。继承自Kernel#test.

2.6.5 :004 > defined?(test)
 => "method" 
2.6.5 :005 > method(:test)
 => #<Method: main.test> 

一个合适的例子是这样的。

2.6.5 :008 > puts @fnord

 => nil 
2.6.5 :009 > puts fnord
Traceback (most recent call last):
        4: from /Users/schwern/.rvm/rubies/ruby-2.6.5/bin/irb:23:in `<main>'
        3: from /Users/schwern/.rvm/rubies/ruby-2.6.5/bin/irb:23:in `load'
        2: from /Users/schwern/.rvm/rubies/ruby-2.6.5/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
        1: from (irb):9
NameError (undefined local variable or method `fnord' for main:Object)

局部变量

错误提示正在发生的事情:歧义。 fnord 可以是局部变量 fnordself.fnord。两者都没有被声明,Ruby 不会猜测你的意思,所以你会得到一个 NameError。

In Ruby local variable names and method names are nearly identical. If you have not assigned to one of these ambiguous names ruby will assume you wish to call a method. Once you have assigned to the name ruby will assume you wish to reference a local variable.

可以使用 local_variables.

发现声明的局部变量
2.6.5 :012 > foo = 42
 => 42 
2.6.5 :013 > Kernel.local_variables
 => [:foo, :_] 

实例变量

An uninitialized instance variable has a value of nil. If you run Ruby with warnings enabled, you will get a warning when accessing an uninitialized instance variable.

有多种方法可以内省实例变量,例如 instance_variables and instance_variables_defined?。虽然在某些情况下这在编写库时可能是必要的,但我 强烈反对 在应用程序代码中利用 nil 和“未定义”之间的区别;它使事情变得脆弱。

Class 变量

Accessing an uninitialized class variable will raise a NameError exception.

全局变量

An uninitialized global variable has a value of nil.