由于在Ruby中一切都是对象,Ruby变量是否存储直接类型的值或地址(读取原语)?与将值存储在变量中的C相比,如果它们是基元。
答案 0 :(得分:8)
注意,以下所有内容都是针对默认的Ruby,它在内部使用YARV aka#34;还有另一个Ruby VM," JRuby等其他红宝石可能会使用不同的内部表示......
好问题。
Ruby使用整数的标记指针,其他所有内容都存储为对象的引用。
他们是如何运作的?指针中的一位用作标记,如果该位置位,则指针的其余部分将被解释为整数,否则将被解释为地址。
这是有效的,因为没有使用指针中的某些位。通常不使用存储器地址的最低位。大多数系统仅允许对齐的存储器地址的地址,例如对齐到4个字节,因此2位可用作标记。然后,如果设置了该标记,则指针的另一个31位将被解释为整数。
当您查看object_id
整数
20.to_s(2) # => "10100"
20.object_id.to_s(2) # => "101001"
在某些系统上使用两个标记位,然后使用另一个标记位表示浮点数。还有一些特殊对象,如nil, true, false
,用保留的数字表示,不太可能是有效的内存地址。符号也在内部表示为带标记的整数,但具有与实际整数不同的位掩码。
所有其他值都表示为指针。
有趣的是,您可以使用ObjectSpace
类自行检查所有这些内容。
(0..100).each { |n| p([n, ObjectSpace._id2ref(n)]) rescue nil }
在我的系统上打印
[0, false]
[1, 0]
[2, 2.0]
[3, 1]
[5, 2]
[6, -2.0]
[7, 3]
[8, nil]
[9, 4]
[10, 2.0000000000000004]
[11, 5]
[13, 6]
[14, -2.0000000000000004]
[15, 7]
[17, 8]
[18, 2.000000000000001]
[19, 9]
[20, true]
[21, 10]
[22, -2.000000000000001]
[23, 11]
...
答案 1 :(得分:4)
tl; dr :没关系,你不能说,而且因为你不能说,Ruby语言规范并没有说关于它的任何事情,它允许不同的实现者做出不同的选择,并且他们做实际上做出了不同的选择。
没关系。
你可以区分的唯一方法就是修改对象,但由于所有直接对象都是不可变的,所以你无法用一种方式说出来。
事实证明,不同的Ruby实现以不同的方式对待它们,并且没有任何问题。例如,YARV将Integer
存储为标记指针(称为 fixnums )或对象引用(称为 bignums ),具体取决于大小,但同样,数字相同可以存储为任一个,因为在64位系统上,它使用63位用于 fixnums ,而在32位系统上,它仅使用31位。 JRuby OTOH没有使用标记指针(它根本不使用指针,因为Java根本没有它们),并且使用完整的64位用于 fixnums 而不管机器字大小,而不是使用31或63位的YARV。
同样,64位系统上的YARV使用62位标记指针格式的Float
s,它们符合62位(他们称之为 flonums ),但在32位系统上和更大的Float
s,它使用不同的编码。
答案 2 :(得分:2)
Ruby中的每个对象都有一个地址。你可以通过这样做obj.object_id << 1
找到它。这是一切都变得有趣但
a = 'Hello'
puts a.object_id << 1 # 140608279312760
a += 'World'
puts a.object_id << 1 # 140608279205240
b = 'HelloWorld'
puts b.object_id << 1 # 140608271586720
c = a
puts c.object_id << 1 # 140608279205240
这表明对象按地址存储在ruby中。此外,除非使用=
,否则地址是唯一的。但请注意,在我们之前的示例中,140608279205240
仅指特定'HelloWorld'
。对a
或c
所做的任何更改都不会影响另一个,但会更改变量的地址并对其进行更改。