Ruby 中的对象地址
简短版本:类的默认inspect
方法显示对象的地址。*我如何在我自己的自定义inspect
方法中执行此操作?
*(需要明确的是,我想要通常从 inspect
获得的 8 位十六进制数字。我不关心实际的内存地址。我只是将其称为内存地址,因为它看起来就像一个,我知道 Ruby 是内存安全的。)
长版本:我有两个类,Thing
和 ThingList.
ThingList
是 Array
的子类,专门用于保存事物。由于事物的性质以及它们在我的程序中使用的方式,事物有一个实例变量 @container
,它指向保存该 Thing 的
。ThingList
两个事物可能具有完全相同的数据。因此,当我调试应用程序时,能够可靠地区分两个事物的唯一方法是使用 inspect
,它会显示它们的地址。然而,当我检查
一个事物
时,我会得到一页又一页的输出,因为inspect
将递归地检查@container
,导致列表中的每个事物也被检查!
我所需要的只是该输出的第一部分。如何在 Thing
上编写仅显示此内容的自定义 inspect
方法?
#<Thing:0xb7727704>
编辑:我刚刚意识到默认的to_s
正是这样做的。我之前没有注意到这一点,因为我有一个自定义的 to_s
,它提供了有关该对象的人类可读的详细信息。
假设我无法使用 to_s
,并且我必须编写自定义 inspect
。
Short version: The default inspect
method for a class displays the object's address.* How can I do this in a custom inspect
method of my own?
*(To be clear, I want the 8-digit hex number you would normally get from inspect
. I don't care about the actual memory address. I'm just calling it a memory address because it looks like one. I know Ruby is memory-safe.)
Long version: I have two classes, Thing
and ThingList
. ThingList
is a subclass of Array
specifically designed to hold Things. Due to the nature of Things and the way they are used in my program, Things have an instance variable @container
that points back to the ThingList
that holds the Thing
.
It is possible for two Things to have exactly the same data. Therefore, when I'm debugging the application, the only way I can reliably differentiate between two Things is to use inspect
, which displays their address. When I inspect
a Thing
, however, I get pages upon pages of output because inspect
will recursively inspect @container
, causing every Thing in the list to be inspected as well!
All I need is the first part of that output. How can I write a custom inspect
method on Thing
that will just display this?
#<Thing:0xb7727704>
EDIT: I just realized that the default to_s
does exactly this. I didn't notice this earlier because I have a custom to_s
that provides human-readable details about the object.
Assume that I cannot use to_s
, and that I must write a custom inspect
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您可以使用 object_id 获取地址并将其乘以 2* 并使用
sprintf
(又名%
)以十六进制显示它:当然,如只要您只需要唯一的数字并且不关心它是否是实际地址,您可以省略
* 2
。* 由于你不需要理解的原因(意思是:我不明白它们),
object_id
返回对象内存地址的一半,所以你需要乘以2 获取实际地址。You can get the address using object_id and multiplying it by 2* and display it in hex using
sprintf
(aka%
):Of course, as long as you only need the number to be unique and don't care that it's the actual address, you can just leave out the
* 2
.* For reasons that you don't need to understand (meaning: I don't understand them),
object_id
returns half the object's memory address, so you need to multiply by 2 to get the actual address.这是不可能的。 Ruby 中无法获取对象的内存地址,因为 Ruby 是一种内存安全语言,它(根据设计)没有直接访问内存的方法。事实上,在 Ruby 的许多实现中,对象甚至没有内存地址。在大多数将对象直接映射到内存的实现中,内存地址可能会在每次垃圾回收后发生变化。
在当前版本的 MRI 和 YARV 中使用内存地址作为标识符意外起作用的原因是它们有一个蹩脚的垃圾收集器实现,永远不会对内存进行碎片整理。所有其他实现都有垃圾收集器,它们对内存进行碎片整理,从而在内存中移动对象,从而更改它们的地址。
如果将实现与内存地址联系起来,那么您的代码将只能在垃圾收集器速度较慢的情况下工作。甚至不能保证 MRI 和 YARV 总是有蹩脚的垃圾收集器,事实上,在这两种实现中,垃圾收集器都已被确定为主要性能瓶颈之一,并且可以安全地假设垃圾收集器将会发生变化。 SVN 中的 YARV 垃圾收集器已经发生了一些重大变化,这将成为 YARV 1.9.3 和 YARV 2.0 的一部分。
如果您需要对象的 ID,请使用
Object#object_id
。This is impossible. There is no way in Ruby to get the memory address of an object, since Ruby is a memory-safe language which has (by design) no methods for accessing memory directly. In fact, in many implementations of Ruby, objects don't even have a memory address. And in most of the implementations that do map objects directly to memory, the memory address potentially changes after every garbage collection.
The reason why using the memory address as an identifier in current versions of MRI and YARV accidentally works, is because they have a crappy garbage collector implementation that never defragments memory. All other implementations have garbage collectors which do defragment memory, and thus move objects around in memory, thereby changing their address.
If you tie your implementation to the memory address, your code will only ever work on slow implementations with crappy garbage collectors. And it isn't even guaranteed that MRI and YARV will always have crappy garbage collectors, in fact, in both implementations the garbage collector has been identified as one of the major performance bottlenecks and it is safe to assume that there will be changes to the garbage collectors. There are already some major changes to YARV's garbage collector in the SVN, which will be part of YARV 1.9.3 and YARV 2.0.
If you want an ID for objects, use
Object#object_id
.您的类实例可以委托给一个类实例来获取所需的方法,而不是对 Array 进行子类化,这样您就不会继承重写的
inspect
方法。Instead of subclassing Array your class instances could delegate to one for the desired methods so that you don't inherit the overridden
inspect
method.