混淆了在一个falsy的`if`块中的赋值操作
我正在玩块内的分配操作,发现了下面的结果,这让我感到吃惊:
C:\>irb --simple-prompt if false x = 10 end #=> nil px nil x.object_id #=> 4 #=> nil py NameError: undefined local variable or method `y' for main:Object from (irb):5 from C:/Ruby193/bin/irb:12:in `<main>'
在上面的代码中,你可以看到x
局部variables已经被创build,即使它只被分配给falsy if
块。 我试图用px
来查看x
的内容,这迫使我相信赋值没有完成,但存在x
variables。 x.object_id
也certificate了是这样的。
现在我的问题是如何创buildx
局部variables即使if
区块入口点被永远closures的故意?
我期望px
的输出与py
的输出相似。 但相反,我从px
得到了一个令人惊讶的答案。
有人能向我解释这个概念是如何工作的吗?
编辑
不,这是另一个testing。 只有local
variables不是这种情况。 instance
和class
variables也是如此。 请看下面:
class Foo def show @X = 10 if false p @X,"hi",@X.object_id end end #=> nil Foo.new.show nil "hi" 4 #=> [nil, "hi", 4] class Foo def self.show @@X = 10 if false p @@X,"hi",@@X.object_id end end #=> nil Foo.show nil "hi" 4 #=> [nil, "hi", 4]
成功案例:
class Foo def self.show @@X = 10 if true p @@X,"hi",@@X.object_id end end #=> nil Foo.show 10 "hi" 4 #=> [10, "hi", 4]
在Ruby中,局部variables是在parsing器首次遇到赋值时定义的,然后在这个范围内。
这里有一个示例:
foo # NameError: undefined local variable or method `foo' for main:Object if false foo = 42 end foo # => nil
正如你所看到的,即使第4行的赋值从未被执行,局部variables也存在于第7行。 然而,它被parsing ,这就是为什么局部variablesfoo
存在。 但是因为这个赋值从来没有被执行过,所以这个variables是未初始化的,因此它的值nil
而不是42
。
在Ruby中,大多数未初始化或甚至不存在的variables的计算结果nil
。 对于局部variables,实例variables和全局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
但是,类层次结构variables和常量不是这样的:
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
你在这里得到一个错误的原因并不是单元化的局部variables不计算nil
,而是fnord
是模棱两可的:它可能是一个无参数的消息发送到默认的接收器(即相当于self.fnord()
) 或者访问局部variablesfnord
。
为了消除歧义,你需要添加一个接收者或者一个参数列表(即使是空的)来告诉Ruby它是一个消息发送:
self.fnord # NoMethodError: undefined method `fnord' for main:Object fnord() # NoMethodError: undefined method `fnord' for main:Object
或者确保parsing器 ( 不是评估者)在使用之前parsing( 不执行)赋值,以告知Ruby它是一个局部variables:
if false fnord = 42 end fnord #=> nil
而且,当然, nil
是一个对象(它是类NilClass
的唯一实例),因此有一个object_id
方法。
Ruby总是分析你的所有代码。 它不会将虚假看作是不parsing内部的标志,而是评估它,并且看到里面的代码不应该被执行
Ruby有局部variables“提升”。 如果你在一个方法的任何地方有一个局部variables的赋值,那么这个variables就存在于方法中的任何地方,甚至在赋值之前,即使赋值永远不会被实际执行。 在分配variables之前,它的值nil
。
编辑:
以上是不正确的。 Ruby确实有一种forms的variables提升,因为当局部variables赋值出现时,它会定义一个局部variables,但是不会被执行。 然而,这个variables不会被定义在上面的分配方法中的点上。