我试图弄清楚 Ruby 如何处理与self
类中的方法同名的局部变量,并发现了一个我不理解的行为:
class A
def val
10
end
def test
val = val
end
end
p A.new.test
此代码打印nil
。为什么?!
我试图弄清楚 Ruby 如何处理与self
类中的方法同名的局部变量,并发现了一个我不理解的行为:
class A
def val
10
end
def test
val = val
end
end
p A.new.test
此代码打印nil
。为什么?!
我认为局部变量一经说明就被声明了。在 ruby 中,查找首先查找局部变量,如果存在则使用它,如果不存在则查找方法。这意味着 val = val 将第一个 val 声明为本地,然后左侧的 val 与之匹配(不确定我应该在显微镜下检查红宝石以确定)
如果你试试
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 调用方法,第二个调用局部变量,大概。
其他答案很好地解释了一切,我只是想向有同样问题的读者指出有关此问题的官方文档。
局部变量和方法
在 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
如果方法的可见性不是公共的或接收者是文字,则使用显式接收者可能会引发 aself
。另一个常见的令人困惑的情况是使用修饰符时
if
:p a if a = 0.zero?
而不是打印“true”,而是收到一个NameError,“未定义的局部变量或方法 'a'”。由于 ruby 解析了第一个的
a
左侧if
并且还没有看到分配给a
它,因此假设您希望调用一个方法。Ruby 然后看到分配给a
并假设您正在引用本地方法。混乱来自表达式的无序执行。首先局部变量被赋值,然后你尝试调用一个不存在的方法。
这是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
变量获取值。
这应该分为两个问题:
当你有a = a
时,首先评估什么?如果你这样做echo 'p a = a' | ruby
,你会得到nil
, 而不是未定义的异常,所以定义是第一位的。
当局部变量与方法同名时会发生什么?答:方法变得不可见,除非你使用self.