4

我的理解是,if行尾的语句在行首的代码之前进行评估:

'never shown' if (false)

并且可以在if语句中进行赋值。

'shown' if (value = 'dave is king')
value #=> "dave is king"

而且,当分配一个不存在的变量时,它就会被创建。没有必要预先存在。这是真的?

如果所有这些假设都是正确的,为什么会失败?

error_array << error if (error = import_value(value))
#=> undefined local variable or method `error' for

它在数组推送之前分配给错误吗?我想了解何时评估事物。

这个确实有效:

if (error = import_value(value))
  error_array << error
end

现在我真的很困惑。

4

3 回答 3

5

仅当您尝试分配文字值时才会发生这种情况,如果您调用它可以工作的函数。

def foo(a)
  a
end

p 'not shown' if(value = foo(false))
p 'shown' if(value = foo(true))

# This outputs a Warning in IRB
p 'shown' if(value = false)
(irb):2: warning: found = in conditional, should be ==

如果您打开调试 (-d),您将看到有关已使用变量的警告value

warning: assigned but unused variable - value

这“有效”是因为该语句确实评估了trueif ,允许它之前的代码运行。

这里发生的是 if() 用作修饰符时具有自己的绑定范围或上下文。因此,该分配永远不会在 if 之外看到,因此执行起来毫无意义。这与 if 控制结构不同,因为 if 语句所采用的块也在与赋值相同的范围内,而 if 修饰符之前的行不在 if 的范围内。

换句话说,这些不是等价的。

if a = some(value)
  puts a
end

puts a if(a = some(value))

前者puts a在 if 的范围内,后者puts a在范围之外,因此具有不同的绑定(ruby 称之为上下文)。

Ruby 操作顺序

于 2013-02-27T02:04:38.547 回答
4

在 Ruby 中,局部变量由解析器在第一次遇到赋值时定义,然后从那时起就在作用域内。由于 Ruby 的解析方式类似于英语,从左到右,从上到下,因此当您使用它时,局部变量还不存在,因为用法离赋值更远。

这是一个小演示:

foo # NameError: undefined local variable or method `foo' for main:Object

if false
  foo = 42
end

foo # => nil

如您所见,局部变量确实存在于第 7 行,即使第 4 行的赋值从未执行过。然而,它被解析了,这就是局部变量foo存在的原因。但是因为从未执行过赋值,所以变量未初始化,因此计算结果为niland not 42

现在让我们来看看你的案例的最简单版本:

bar if bar = true
# warning: found = in conditional, should be ==
# NameError: undefined local variable or method `bar' for main:Object

bar # => true

该变量是在解析赋值时创建的,这里是:

bar if bar = true
       ^^^^^^^^^^

但它在这里使用:

bar if bar = true
^^^

这是分配之前。赋值在使用之前执行的事实是无关紧要的,因为在这里解析是相关的,并且赋值在使用之后被解析,这意味着在使用点解析器仍然认为它是一个没有参数列表和隐式的方法调用接收者(即等同于self.bar())而不是局部变量。

于 2013-02-27T12:16:33.087 回答
2

我的猜测是解析顺序与(逻辑)执行顺序不同。特别是,给定

array << error if (error = some_function)

然后从逻辑上讲,执行应该类似于

  1. 称呼some_function
  2. 如果error没有定义,定义error
  3. 将返回值分配给some_functiontoerror
  4. 评估if
  5. 如果if计算结果为true,则附加errorto的值array

然而,解析明智(假设典型的 LR 解析器),它去

  1. 得到令牌array(标识符)。这是定义的吗?是的。它是一个变量吗?是的。
  2. 得到令牌<<(操作员)。有array回应<<吗?是(否则,输出“未定义方法”错误)。
  3. 得到令牌error(标识符)。这是定义的吗?否。输出“未定义的局部变量或方法”。
于 2013-02-27T02:22:56.340 回答