在Ruby中不存在“立即值”的概念
现在,你可能会问:“为什么Ruby FAQ谈到了立即值,而Ruby并没有立即值?”这个问题的答案是,不幸的是,在Ruby社区的很多文档中,混淆了被称为“Ruby”的编程语言的概念和许多Ruby实现之一的概念,这个实现也经常被称为“Ruby”,尽管它的“官方”名称是“YARV”。
例如,如果你查看ISO/IEC 30170:2012 信息技术-编程语言-Ruby规范,你将找不到任何有关立即值的提及,无论是以这个名字还是以其他任何名字类似的概念。它们根本不存在。
请注意,在你链接到的关于立即值的部分中,还有以下警告:
这个部分或其中的某些部分可能已经过时或需要确认。
所以,我们有两个问题:
- 这一部分仅涉及 Ruby 的一个具体实现,而不是所有实现,但它并没有明确说明这一点;
- 即便是与具体实现有关的信息也已过时。
在当前版本的 YARV 中,Fixnum
已经不存在了。过去,Integer
是一个抽象类,有两个具体子类:Fixnum
和 Bignum
。 Fixnum
是立即数,而 Bignum
则不是。
然而,根据你是在32位还是64位运行,完全相同的文字可能是
Fixnum
(即立即值),也可能是
Bignum
。在32位系统上,
Fixnum
可以存储31位,在64位系统上,
Fixnum
可以存储63位。请注意,这仅适用于YARV,例如
JRuby将在32位和64位平台上都存储64位(不仅仅是63位)
。
现在,Fixnum
和Bignum
已不存在,Integer
是一个具体类,而不是抽象类。但是,优化实际上仍在进行:YARV在32位系统上仍将31位的Integer
优化 为fixnum,在64位系统上将63位的Integer
优化,而JRuby则 仍然 优化64位的Integer
。
JRuby长期以来一直优化了
Float
。在JRuby中,
Float
是即时值。然而,在YARV中,没有这样的优化。
Float
不是即时值。然而,最近,YARV引入了
flonum的概念。
Flonum是适合于62位的
Float
。
Flonum是即时值。此外,此优化仅在64位平台上执行,在32位平台上完全禁用
flonum。
还要注意的是,FAQ完全忽略了
Symbol
,它们是许多实现中的即时值,包括YARV。
因此,回答您的问题:
Ruby中的float是即时值吗?
不是。也许。有些时候是。
如果您所说的“Ruby”是指“Ruby编程语言”,则
Float
在Ruby中不是即时值。 Ruby
Language没有即时值的概念。
也许在Ruby中,
Float
是立即值,也可能不是,如果你指的是“所有现有的Ruby实现集合”,则情况各不相同。在一些实现中,在某些情况下,一些
Float
值可能是或可能不是立即值。
如果你指的是“YARV”,一些
Float
值有时是立即值。在64位平台上,
Float
的一个子集是立即值,但并非全部。在32位平台上,没有任何
Float
是立即值。
这是无关紧要的。
你只能通过变异来确定一个值是否为立即值。但是,所有进行此类优化的值都是
不可变的,不能有实例变量,也不能有单例方法或单例类。
因此,实际上不可能确定某个东西是否为立即值。这是一个私有的内部优化细节。
这意味着你可以完全忽略这个概念,因为它无法使你的程序运行不同。
那么
object_id
呢?
首先:
Object#object_id
是一个可恶的东西,它不应该存在。最好忘记你曾经听说过它。
它违反了面向对象编程的基本原则之一,即模拟另一个对象的对象应该与该对象无法区分。(同样适用于
BasicObject#equal?
。)
但第二个例子是这样的:
s1 = '1'
s2 = '1'
s1.object_id
s2.object_id
糟糕,我破坏了你的测试:冻结的String
字面值不是直接对象,但它们会自动去重。