【发布时间】:2017-05-08 11:50:06
【问题描述】:
在开发 Ruby 程序时,我希望将一些状态数据从实例变量移动到类变量,但我突然意识到,虽然实例变量是自动激活的(如果您尝试在“不初始化”它们的情况下读取它们,它们是自动初始化为nil),类变量不是 - 这对我来说看起来很不一致(与大多数非常一致的Ruby语法相比)。
示例程序:
class Test
def id
@id.to_i
end
def id=(i)
@id = i
end
def nextid
self.id = id + 1
end
end
t = Test.new
puts t.nextid #=> 1
puts t.nextid #=> 2
在这种情况下,当调用Test::id时,如果@id没有初始化,Ruby会自动将其激活为nil(之后我to_i它得到0)。
现在我决定要在 Test 实例之间共享运行 ID,因此我将其重写如下:
class Test
def id
@@id.to_i
end
def id=(i)
@@id = i
end
def nextid
self.id = id + 1
end
end
t = Test.new
puts t.nextid
puts t.nextid
我想应该是一样的,但是不行:
NameError: uninitialized class variable @@id in Test
但是这种解决方法有效(!?):
class Test
def id
(@@id ||= 0).to_i
end
def id=(i)
@@id = i
end
def nextid
self.id = id + 1
end
end
t = Test.new
puts t.nextid #=> 1
puts t.nextid #=> 2
(当然,在对0 进行惰性初始化后,我可以删除to_i,但为了保持一致性,我保留了它)。
看起来 Ruby 理解“延迟初始化”并将其视为不抛出 NameError 所需的魔法——即使 ||= 应该只是 x = x || val 的语法糖(顺便说一句,它不适用于初始化类变量,谢谢提问)。
怎么会?
【问题讨论】:
-
x ||= val有点等价于x || x = val,而不是x = x || val。另外,在你的代码中,你为什么要一个实例方法来设置一个类变量? -
您测试的是哪个 ruby 版本?我在 ruby-2.2.2 中尝试过第二种情况,我得到的是
NoMethodError: undefined method '+' for nil:NilClass而不是NameError: uninitialized class variable @@id -
@fangxing:我不认为这取决于 Ruby 版本。我会说这是问题中的错字。您可以使用
self.id = id + 1来获取提到的错误。 -
||=可以很好地初始化类变量。你到底有什么问题? -
@EricDuminil - re
||=是例如我不需要的变量。为什么类变量需要它而实例变量不需要?另外,如果x是@@x,x || x = val也不会工作。
标签: ruby class-variables