【问题标题】:Ruby object to_s what is the encoding of the object id?Ruby 对象 to_s 对象 id 的编码是什么?
【发布时间】:2018-08-17 14:41:42
【问题描述】:

在 Ruby 中,对象上的 to_s 包含对象 id 的编码。

[2] pry(main)> shape = Shape.new(4,4)
=> #<Shape:0x00007fac5eb6afc8 @num_sides=4, @side_length=4>

在文档中说

返回一个表示 obj 的字符串。默认 to_s 打印对象的类和对象id 的编码。 https://apidock.com/ruby/Object/to_s

在上面的例子中,对象id的编码是0x00007fac5eb6afc8

How does object_id assignment work? 他们解释了

在 MRI 中,对象的 object_id 与在 C 级别上表示对象的 VALUE 相同。

所以我对比了object_id,和对象id的编码不一样。

[2] pry(main)> shape = Shape.new(4,4)
=> #<Shape:0x00007fac5eb6afc8 @num_sides=4, @side_length=4>
[3] pry(main)> shape.object_id
=> 70189150066660

对象 id 的编码到底是什么?它似乎不是object_id

【问题讨论】:

标签: ruby object document tostring


【解决方案1】:

object_id__id__ 视为对象的“指针”。它在技术上不是一个指针,但确实包含一个唯一值,可用于检索内部 C VALUE

它对某些数据类型的值有一定的模式,正如您可以看到它的十六进制表示形式为to_s。我不会详细介绍所有细节,因为已经有很多关于 SO 解释的答案,并且已经从 cmets 链接,但是整数(高达 FIXNUM_MAX,具有可预测的值,以及像 true、@987654327 这样的特殊常量@ 和 nil 在每次运行中将始终具有相同的 object_id

简单地说,它只是一个数字,显示为十六进制(以 16 为基数)值,而不是任何实际的“编码”或密码。

根据您对问题的最新编辑,将对此进行更多扩展。正如您发布的那样,您在to_s 中看到的十六进制数字是对象的内部C VALUE 的值。 VALUE 是一种 C 数据类型(无符号,指针大小数字),每个 Ruby 对象都用 C 代码表示。正如@Stefan 在评论中指出的那样,对于非整数类型(我只说 MRI 版本),它是 object_id 值的两倍。不是你可能关心,但你可以移动一个整数的位来预测它们的值。

因此,以你为例。

0x00007fac5eb6afc8 的值是数字的简单十六进制表示法。它使用以 16 为基数的计数系统,而不是我们在日常生活中更习惯的以 10 为基数的十进制系统。这只是查看相同数字的不同方式。

所以,使用这个逻辑。

a = 0x00007fac5eb6afc8
#=> 140378300133320 # Decimal representation

a /= 2 # Remember, non-integers are half of this value
#=> 70189150066660   # Your object_id

【讨论】:

  • 感谢您的澄清!我现在明白了。
  • @MicFin 没问题 ;)
  • 我想知道为什么 Ruby object_id 将 C VALUE 除以二。
【解决方案2】:

你能得到的最好答案是:你不知道,你不应该知道。

Ruby 准确地保证了关于对象 ID 的三件事:

  1. 对象在其生命周期内具有相同的 ID。
  2. 没有两个对象同时具有相同的 ID。
  3. ID 是整数。

特别是,这意味着您不能依赖具有特定 ID 的特定对象(例如,nil 具有 ID 8)。这也意味着可以重复使用 ID。您应该将其视为不透明的标识符。

而且,正如您所引用的,默认 Object#to_s 使用 ID 的“某些”编码。

这就是你所知道的一切,也是你应该依赖的一切。特别是,您应该切勿尝试解析 ID 或 Object#to_s

所以,Object#to_s 的 ID 部分是 ID 的“一些未指定的编码”,它本身就是“一些不透明的标识符”。

其他所有内容都故意未指定,以便不同的实现可以根据其特定需求做出不同的选择。例如,将对象 ID 绑定到内存地址是愚蠢的,因为 JRuby、Opal、IronPython、MagLev 和 Topaz 等实现运行在甚至不存在“内存地址”概念的平台上! Rubinius 使用移动垃圾收集器,对象可以在内存中移动,从而改变它们的地址。

【讨论】:

    猜你喜欢
    • 2010-09-14
    • 2022-01-25
    • 1970-01-01
    • 2017-06-14
    • 1970-01-01
    • 2011-06-12
    相关资源
    最近更新 更多