Ruby变量存储值或地址吗?

时间:2016-12-29 20:17:21

标签: ruby

由于在Ruby中一切都是对象,Ruby变量是否存储直接类型的值或地址(读取原语)?与将值存储在变量中的C相比,如果它们是基元。

3 个答案:

答案 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'。对ac所做的任何更改都不会影响另一个,但会更改变量的地址并对其进行更改。