我试图弄清楚Ruby如何处理与self
类中的方法具有相同名称的局部变量,并发现了一个我不理解的行为:
class A
def val
10
end
def test
val = val
end
end
p A.new.test
此代码打印nil
。为什么?!
答案 0 :(得分:4)
我认为局部变量一旦声明就会被声明。在ruby中,查找首先查找局部变量,如果它存在则使用它,如果不存在则查找方法。这意味着val = val将第一个val声明为local,然后左手val将其匹配(不确定它我应该检查ruby under microscope以确定)
如果您尝试
class A
def val
10
end
def test
back = []
x = val
back << x
val = x + 1
back << val
x = val
back << x
end
end
p A.new.test
然后一切都很好,打印[10,11,11],这意味着第一个x = val调用方法,第二个调用局部变量,大概是。
答案 1 :(得分:0)
这是nil
,因为val
是您尝试传递的方法,并且您不会在任何地方调用val
并且它会覆盖自己。你基本上陷入了困境。
在每个函数的最后是一个隐式返回,它返回最后一个值,如果它没有值返回Ruby返回nil
,但你可能期望一个函数?
这在Python中类似,其中没有返回的函数总是返回None
。
这可以通过将左手val
转换为具有@
内涵的实例属性来解决。
我猜你想要用10
方法打印val()
吗?
def test
@val = val()
end
puts A.new.test
以下也有效:
def test
val = self.val() #but this will produce the same as above to no real benefit.
end
关键是您必须调用val
方法才能使val
变量获取值。
答案 2 :(得分:0)
这应该分为两个问题:
当你有a = a
时,首先评估什么?如果你执行echo 'p a = a' | ruby
,则得到nil
,而不是未定义的异常,因此首先定义。
当局部变量与方法具有相同名称时会发生什么?答案:除非您使用self.
答案 3 :(得分:0)
其他答案解释一切正常我只是想向读者提出official documentation相同的问题。
在Ruby中,局部变量名和方法名几乎相同。如果你没有分配给其中一个含糊不清的名字,ruby会假设你想调用一个方法。一旦你分配了名称,ruby就会假设你想引用一个局部变量。
当解析器遇到赋值时创建局部变量,而不是在赋值发生时创建:
a = 0 if false # does not assign to a p local_variables # prints [:a] p a # prints nil
方法和局部变量名称之间的相似性可能会导致代码混淆,例如:
def big_calculation 42 # pretend this takes a long time end big_calculation = big_calculation()
现在对
big_calculation
的任何引用都被视为局部变量并将被缓存。要调用该方法,请使用self.big_calculation
。 您可以使用如上所示的空参数括号或使用self.
之类的显式接收器强制进行方法调用。如果方法的可见性不公开,则使用显式接收器可能会引发NameError。另一个令人困惑的情况是使用修饰符
if
:p a if a = 0.zero?
您不会打印“true”,而是会收到NameError,“未定义的局部变量或方法`a&#39;”。由于ruby首先解析
a
左侧的if
,但尚未看到a
的赋值,因此它假设您希望调用方法。然后Ruby看到a
的赋值,并假设您引用了一个本地方法。混淆来自表达式的无序执行。首先分配局部变量,然后尝试调用不存在的方法。