我的理解是该行末尾的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
现在我真的很困惑。
答案 0 :(得分: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
这个“有效”,因为该语句确实评估为true
,并允许其前面的代码运行。
这里发生的是if()当用作修饰符时它有自己的绑定范围或上下文。因此,在if之外永远不会看到赋值,因此执行起来没有任何意义。这与控制结构不同,因为if语句所采用的块也与赋值在同一范围内,而if修饰符之前的行不在if的范围内。
换句话说,这些并不等同。
if a = some(value)
puts a
end
puts a if(a = some(value))
前者在if的范围内有puts a
,后者在范围之外有puts a
,因此具有不同的绑定(ruby称之为上下文)。
答案 1 :(得分:4)
在Ruby中,局部变量在首次遇到赋值时由解析器定义,然后从该点开始在范围内。由于Ruby被解析为英语,从左到右,从上到下,当你使用它时,本地变量还不存在,因为使用还远离了赋值。
这是一个小小的演示:
foo # NameError: undefined local variable or method `foo' for main:Object
if false
foo = 42
end
foo # => nil
如您所见,即使第4行的赋值从未执行过,第7行也存在局部变量 。然而,它是解析,这就是本地变量foo
存在的原因。但由于赋值从未执行过,因此该变量未初始化,因此评估为nil
而不是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()
),而不是局部变量。
答案 2 :(得分:2)
我的猜测是解析的顺序与(逻辑)执行顺序不同。特别是,给定
array << error if (error = some_function)
然后逻辑上,执行应该像
some_function
error
未定义,请定义error
some_function
的返回值指定为error
if
if
评估为true
,则将error
的值附加到array
然而,解析明智(假设是典型的LR解析器),它就是
array
(标识符)。这个定义了吗?是。它是变量吗?是。<<
(运营商)。 array
会回复<<
吗?是(否则,输出“未定义方法”错误)。error
(标识符)。这个定义了吗?编号输出“未定义的局部变量或方法”。