更新:我的思维模式在这里出错了。方法f
定义了一个参数a
。如果我将这个参数命名为b
,那么f
确实会返回'oh'
而不是“2”。
感谢下面的@Holgur帮助我重新分析并看到我的错误。
考虑方法f
,
def f(a)
return a = 2 if !a.nil?
return 'oh'
end
f(42) # 2
f(nil) # 'oh'
考虑方法g
,
def g(b)
return a = b if !a.nil?
return 'oh'
end
g(42) # 'oh'
g(nil) # 'oh'
考虑方法h
,
def h(b)
a = b
return a if !a.nil?
return 'oh'
end
h(42) # 42
h(nil) # 'oh'
我期望g(42)
返回42
?为什么g(42)
不返回42
?
此处f
和g
之间以及g
和h
之间的差值的计算顺序是什么?
2条答案
按热度按时间prdp8dxp1#
大致相当于
因此,Ruby首先测试
a
是否不为nil(这是假的,因为a
实际上是nil
,因为它还没有被赋值),因此,if
的主体不执行,沿着执行return 'oh'
。然而,这里更重要的问题是:为什么这样做的工作在所有和没有导致一个错误,如
NameError:未定义局部变量或方法'a'
尝试访问
if
中的a
变量时,即使它之前未初始化。这是因为Ruby会用
nil
初始化变量,如果它们出现在代码赋值语句的左边,即使变量实际上可能没有被赋值。这个行为在https://stackoverflow.com/a/12928261/421705中有进一步的解释。按照这个逻辑,你的代码只能使用你原来的inline-
if
,但是如果使用块形式if
,就会失败,因为使用这个更长的形式,a
只能在if
块中初始化,这里,你会得到NoMethodError
。8yoxcaq72#
正如@HolgerJust指出的,这是一个词法分析问题。
使用 * 修饰符-[if/unless]* 还有其他一些类似的有趣副作用
下面是解析器对它的简单理解:
1.定义方法
a()
1.然后解析器会遇到
a
作为 then 主体的一部分,所以它将这个a
标记为方法调用(a()
),因为a
在这里不是局部变量,并且ruby语法允许在方法调用中省略括号。1.解析器然后遇到 test expression,在这里它将
a
标记为局部变量,因为赋值(=
)1.执行 * 测试表达式 *,并在过程中将
a
赋值为true
,测试通过1.现在执行调用
a()
方法的 then 主体,因为这是#2中标识引用a
的方式,这导致表达式(a if a = true)
返回1
。1.然而,如#4中所指出的,对
a
的赋值也发生了,因此该比较变为(1) == true
**注意:**如果您删除方法定义,这将由于#2而引发
NameError
,但仍将进行局部变量赋值。