【问题标题】:In Ruby why won't `foo = true unless defined?(foo)` make the assignment?在 Ruby 中,为什么 `foo = true 除非已定义?(foo)` 进行赋值?
【发布时间】:2010-02-18 19:39:57
【问题描述】:

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

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

谢谢

【问题讨论】:

  • 你使用的是什么版本的 Ruby?
  • 所有这些关于分配变量的讨论,除非它们已经定义,我不得不指出foo ||= true 完成了同样的事情(并且总是返回true)。
  • @Allison R. 如果foo 已定义但为假,则不是。
  • 我建议您使用更具描述性的标题,而不是使用诸如“Ruby 中发生了什么?”之类的模糊标题。至少,您应该在标题中包含“除非”一词。这样如果有人遇到同样的问题,他们可以根据问题的标题知道这个问题可能是相关的。
  • 在一行中更好的方法是defined?(foo) or foo = true

标签: ruby


【解决方案1】:

显然,ruby 在解析时创建了局部变量,将它们设置为nilso 它被定义并且无论代码是否执行都是如此。

在您的第一行评估代码时,它不会执行赋值部分,因为foo 设置为nil。在第二行中,由于fooo还没有被解析,defined?返回nil让块内的代码执行并赋值fooo

作为一个例子,你可以试试这个:

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

本文摘自 ruby​​-forum 的论坛 post

【讨论】:

  • 优秀的例子 - 应该考虑将问题进一步简化为您展示的问题。谢谢。
【解决方案2】:

让我们从更简单的开始:

# 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 是我们块的返回值。

【讨论】:

    【解决方案3】:
    irb(main)> foo = true unless defined?(Integer)
    => nil 
    irb(main)> foo = true unless defined?(thisIsUndefined)
    => true
    

    您的第一个块返回 nil,因为它的编写方式留下了 2 个选项:

    • 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(在行首),即使您仍在定义它。

    【讨论】:

      【解决方案4】:

      首先在赋值语句中调用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
      

      【讨论】:

        【解决方案5】:

        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"
        

        【讨论】:

          【解决方案6】:

          嗯.. 一种形式是块,一种形式不是。第二部分,块,返回最后评估的语句。第一个.. Hrm..我不知道它在做什么。

          【讨论】:

            【解决方案7】:

            在 Ruby 1.8.7 中:

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

            我无法解释您所看到的行为。

            【讨论】:

            • fooo(相对于foo)是真的。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-04-16
            • 2019-12-29
            • 1970-01-01
            • 2011-03-12
            • 1970-01-01
            • 2010-12-12
            • 1970-01-01
            相关资源
            最近更新 更多