在Ruby中为什么不会`foo = true除非定义?(foo)`进行赋值?

时间:2010-02-18 19:39:57

标签: ruby

这里发生了什么?两种形式“除非”之间的细微差别是什么?

> irb(main):001:0> foo = true unless defined?(foo)
=> nil 
irb(main):002:0> unless defined?(fooo) ; fooo = false ; end
=> false 

THX

7 个答案:

答案 0 :(得分:16)

显然,ruby在解析时创建局部变量,将它们设置为nil,因此它已定义,无论代码是否执行,都会执行此操作。

在第一行评估代码时,由于foo设置为nil,因此不会执行分配部分。在第二行中,由于尚未解析fooodefined?返回nil,让块内的代码执行并分配fooo

举个例子,你可以试试这个:

if false  
  foo = 43  
end  
defined? foo  
=> "local-variable"

这是来自ruby-forum的论坛post

答案 1 :(得分:12)

让我们从更简单的事情开始:

# 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

有关如何分配(甚至那些未执行的分配)导致变量存在的更多信息,请参阅Variable/Method Ambiguity的讨论。

在你的第二个例子中,没有任何神秘之处:fooo未定义,因此块中的代码执行,将fooo设置为false。该赋值是最后一个求值表达式,因此false是块的返回值。

答案 2 :(得分:2)

irb(main)> foo = true unless defined?(Integer)
=> nil 
irb(main)> foo = true unless defined?(thisIsUndefined)
=> true

你的第一个区块正在返回nil,因为它的编写方式有两个选项:

  • foo未定义 - >指定真实
  • 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(在行的开头),即使您仍在定义它。

答案 3 :(得分:1)

在第一个实例中,您在赋值语句中调用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

答案 4 :(得分:1)

8月,在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"

答案 5 :(得分:-1)

嗯..一个表单是一个块而一个表单不是。第二部分,块,返回评估的最后一个语句。第一个...... Hrm ..我不确切知道它在做什么。

答案 6 :(得分:-1)

在Ruby 1.8.7中:

foo = true unless defined?(foo)
p foo # => nil

unless defined?(fooo); fooo = true; end
p foo # => nil

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