ruby – 与错误的`if`块内的赋值操作混淆
参见英文答案 >
I don’t understand ruby local scope????????????????????????????????????5个
我正在玩if块中的赋值操作,并发现了以下结果,这让我感到惊讶: C:&;irb --simple-prompt if false x = 10 end #=> nil p x nil x.object_id #=> 4 #=> nil p y NameError: undefined local variable or method `y' for main:Object from (irb):5 from C:/Ruby193/bin/irb:12:in `<main>' 在上面的代码中,您可以看到x局部变量已经创建,即使它仅被分配给falsy if块.我试图用p x来查看x的内容,这迫使我相信分配没有完成,但x变量存在. x.object_id也证明了这种情况. 现在我的问题是如何创建x局部变量,即使if块入口点是故意关闭的? 我期望p x的输出类似于p y的输出.但相反,我从p x得到了一个令人惊讶的答案. 有人可以向我解释这个概念是如何运作的吗? 编辑 不,这是另一个测试.仅局部变量不是这种情况.实例和类变量也是如此.见下文: class Foo def show @X = 10 if false p @X,"hi",@X.object_id end end #=> nil Foo.new.show nil "hi" 4 #=> [nil,4] class Foo def self.show @@X = 10 if false p @@X,@@X.object_id end end #=> nil Foo.show nil "hi" 4 #=> [nil,4] 成功案例: class Foo def self.show @@X = 10 if true p @@X,@@X.object_id end end #=> nil Foo.show 10 "hi" 4 #=> [10,4] 解决方法
在Ruby中,局部变量在首次遇到赋值时由解析器定义,然后从该点开始在范围内.
这是一个小小的示范: foo # NameError: undefined local variable or method `foo' for main:Object if false foo = 42 end foo # => nil 如您所见,即使第4行上的赋值从未执行过,第7行也存在局部变量.然而,它被解析了,这就是本地变量foo存在的原因.但由于赋值从未执行过,因此该变量未初始化,因此计算结果为nil而不是42. 在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 当然,nil是一个对象(它是类NilClass的唯一实例),因此有一个object_id方法. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |