【问题标题】:Ruby: method inexplicably overwritten and set to nilRuby:方法被莫名其妙地覆盖并设置为零
【发布时间】:2023-03-14 10:40:02
【问题描述】:

如果我执行这个 ruby​​ 代码:

def foo
  100
end

p defined?(foo), foo
if false
  foo = 200
end
p defined?(foo), foo

我得到的输出是:

"method"
100
"local-variable"
nil

有人可以向我解释为什么 foo 在不执行 if 后设置为 nil 吗?这是预期的行为还是 ruby​​ 错误?

【问题讨论】:

  • 方法不被覆盖,设置为nil。 puts foo() 仍然有效。发生的事情是局部变量foo 已经存在。抱歉,我无法回答为什么会这样。
  • 我也无法回答为什么。但是,如果局部变量和方法之间存在歧义,请务必使用self.foo 表示方法,使用foo 表示变量。
  • @sawa - 我不会再回滚,但我不明白你的评论,我不明白你为什么改变 bmesuere 的问题。这个问题没有错。我认为不需要编辑它。
  • @Mischa 我改了三点。 1、puts不输出nil。它必须是p。 2. 不需要额外定义一个方法并调用它。将其删除并直接放置将使读者友好。 3. 输出defined?值更自然、更友好
  • @sawa - 你的观点是有效的,我只是说这个问题没有你的编辑是完全可以理解的。如果是代码审查,我会同意,但我不明白您为什么必须更改问题。此外,现在的方式,bmesuere 得到的输出,与 your 代码不对应。

标签: ruby local-variables


【解决方案1】:

分配左侧的名称设置为nil,即使在if false 的情况下无法访问代码。

>> foo
NameError: undefined local variable or method `foo' for main:Object
...
>> if false
..   foo = 1
..   end #=> nil
>> foo #=> nil

当 Ruby 尝试解析裸字时,它首先会查找局部变量(在 Pickaxe 书中对此有参考,目前我似乎无法找到)。由于您现在有一个名为 foo 的名称,因此它显示为 nil。正如Mischa 所说,该方法仍然可以称为foo()

【讨论】:

  • 如果我理解得很好,当 ruby​​ 解析代码时,会创建一个本地 foo 变量,即使该代码可能永远不会被执行?
  • 只要变量位于赋值的左侧,就可以。顺便说一句:由于您是 SO 新手,因此这里的礼仪是支持和/或接受有用的答案。如果您还有其他问题,我很乐意更新我的答案。
  • 对不起,我之前的评论不是很清楚。我的意思是问变量是否仅在解析时“保留”,或者是否还分配了内存(这似乎非常低效)?
  • 变量只是一个指向nil的引用,它是一个单例对象(它只有一个实例)。
【解决方案2】:

这是我的朋友兼 Ruby 超级专家 Josh Cheek 所说的:

当 Ruby 看到赋值时,它会在当前范围内初始化变量并将其设置为 nil。由于分配没有运行,它没有更新 foo 的值。

if 语句不会像块那样改变范围。这也是最重要的区别

for x in xs

xs.each { |x| }

这是另一个例子:

a = 123 if a  # => nil
a  # => nil

我们不应该说if a,因为我们从未设置a,但是Ruby看到a = 123并初始化a,然后到达if a,此时a是@987654331 @

我认为这是解释器的一个怪癖,真的。 Gary Bernhardt 在 wat (https://www.destroyallsoftware.com/talks/wat) 和 a = a 取笑它

-乔什

【讨论】:

    猜你喜欢
    • 2014-11-07
    • 2014-01-23
    • 2012-03-12
    • 2012-07-01
    • 1970-01-01
    • 2012-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多