在Ruby中为什么不会`foo = true除非定义?(foo)`进行赋值?
这里发生了什么? 两种forms“除非”之间的细微差别是什么?
> irb(main):001:0> foo = true unless defined?(foo) => nil irb(main):002:0> unless defined?(fooo) ; fooo = false ; end => false
谢谢
显然,ruby在解析时创建局部变量,将它们设置为nil
以便定义它,无论代码是否执行,都会执行此操作。
当在第一行评估代码时,它不会执行赋值部分,因为foo
设置为nil
。 在第二行,因为还没有解析fooo
, defined?
返回nil
让块内的代码执行并分配fooo
。
举个例子,你可以尝试这个:
if false foo = 43 end defined? foo => "local-variable"
这是从ruby-forum的论坛post中获取的。
让我们从更简单的事情开始:
# z is not yet defined irb(main):001:0> defined?(z) => nil # Even though the assignment won't execute, # the mere presence of the assignment statement # causes z to come to life. irb(main):002:0> z = 123 if false => nil irb(main):003:0> defined?(z) => "local-variable" irb(main):004:0> z => nil
现在我们可以找出你的第一个例子。
foo = true unless defined?(foo)
foo
定义了吗? 在我们按下irb
ENTER之前,没有。 但是,赋值语句的存在会导致foo
变为现实。 这意味着赋值语句不会被执行,只留下foo
但其值为nil
。 在irb
线中评估的最后一个表达式是什么? unless defined?(foo)
,它的结果nil
。
有关如何分配(甚至那些未执行的分配)导致变量存在的更多信息,请参阅变量/方法歧义的讨论。
在你的第二个例子中,根本没有任何神秘之处: fooo
,因此块中的代码执行,将fooo
设置为false
。 该赋值是最后一个求值表达式,因此false
是块的返回值。
irb(main)> foo = true unless defined?(Integer) => nil irb(main)> foo = true unless defined?(thisIsUndefined) => true
你的第一个块返回nil
因为它的编写方式有两个选项:
-
foo
未定义 – >赋值为true -
foo
被定义 – >什么都不做
这里,必须在计算线时定义foo。 因此,没有任何反应,返回nil
。
irb(main)> unless defined?(Integer) ; fooo = false ; end => nil irb(main)> unless defined?(thisIsUndefined) ; fooo = false ; end => false
您的第二个块的运行方式与第一个块的运行方式相同。 如果fooo
,则输入块并将fooo
设置为false
。 块的最后一行的结果是块的返回值,因此您看到的是false
。 如果fooo
确实存在,则跳过该块并且没有任何反应,因此没有任何东西可以返回,因此nil
。
根据您的代码,我会说foo
是在运行此代码时定义的,而fooo
则不是(测试代码显示在Ruby 1.8.6中生成)。 如果你在运行这段代码之前没有定义其中任何一个,那么你可能会有一个名为foo
东西,它是默认定义的(自defined?(foo)
来检查)。 尝试使用其他名称,看看是否得到相同的结果。
编辑:
irb(main)> defined?(bar) => nil irb(main)> bar = true unless defined?(bar) => nil irb(main)> defined?(bar) => "local-variable"
显然, defined?()
返回true,因为它已经看到bar
(在行的开头),即使你仍然在定义它。
在第一个实例中,您在赋值语句中调用foo
。 也许这会澄清:
bar = if true puts bar.class else puts "not reached" end NilClass => nil baz = if true puts baz.class 42 else puts "not reached" end NilClass => 42
八月,1.8.7都很好看:
$ irb irb(main):001:0> unless defined?(fooo); fooo = true; end => true irb(main):002:0> fooo => true irb(main):003:0> `ruby --version` => "ruby 1.8.7 (2008-06-20 patchlevel 22) [i486-linux]\n"
嗯..一个表单是块,一个表单不是。 第二部分,即块,返回最后评估的语句。 第一个……嗯..我不确切知道它在做什么。
在Ruby 1.8.7中:
foo = true unless defined?(foo) p foo # => nil unless defined?(fooo); fooo = true; end p foo # => nil
我对你所看到的行为没有解释。