在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 。 在第二行,因为还没有解析fooodefined? 返回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 

我对你所看到的行为没有解释。