在朱莉娅,我说变量有一个nextInt
但是忘记了它的名字,如何使用id检索对象?
即。我想要object_id
的倒数。
答案 0 :(得分:8)
正如@DanGetz在评论中所说,object_id
是一个哈希函数,并且设计为不可逆。 @phg也是正确的ObjectIdDict
正是为了这个目的而准备的(documented虽然在手册中没有多少讨论):
ObjectIdDict([itr])
ObjectIdDict()
构造一个哈希表,其中键是(总是) 对象身份。与Dict
不同,它的键和参数不是参数化的 值类型,因此其eltype始终为Pair{Any,Any}
。请参阅
Dict
以获取进一步的帮助。
换句话说,它使用===
作为哈希函数,通过object_id
哈希对象。如果你有一个ObjectIdDict
而你使用你遇到的对象作为其中的键,那么你可以保留它们并稍后通过将它们从ObjectIdDict
中取出来恢复这些对象。
然而,听起来你只想通过询问创建的对象是否具有给定的ObjectIdDict
而没有明确的object_id
。如果是这样,请考虑这个思想实验:如果每个对象总是可以从其object_id
恢复,那么系统永远不会丢弃任何对象,因为程序总是可以通过ID请求该对象。所以你永远无法收集任何垃圾,每个程序的内存使用量会迅速扩大,以便使用你所有的RAM和磁盘空间。这相当于只有一个全局ObjectIdDict
,您可以将每个对象都放入其中。因此,以这种方式反转object_id
函数将永远不需要释放任何对象,这意味着您需要无限制的内存。
即使我们有无限的记忆,也存在更深层次的问题。对象存在意味着什么?在存在优化编译器的情况下,这个问题没有明确的答案。从程序员的角度来看,通常会出现一个对象被创建和操作,但实际上 - 即从硬件的角度来看 - 它永远不会被创建。考虑这个函数,它构造一个复数,然后用它来进行简单的计算:
julia> function f(y::Real)
z = Complex(0,y)
w = 2z*im
return real(w)
end
f (generic function with 1 method)
julia> foo(123)
-246
从程序员的角度来看,这构造了复数z
,然后构造2z
,然后2z*im
,最后构造real(2z*im)
并返回该值。因此,所有这些值都应该插入到“天空中的Great ObjectIdDict”中。但它们真的构建了吗?以下是应用于Int
的此函数的LLVM代码:
julia> @code_llvm foo(123)
define i64 @julia_foo_60833(i64) #0 !dbg !5 {
top:
%1 = shl i64 %0, 1
%2 = sub i64 0, %1
ret i64 %2
}
根本没有构建Complex
个值!相反,所有工作都被内联并消除,而不是实际完成。整个计算归结为将参数加倍(通过将其向左移一位)并将其否定(通过从零中减去)。这种优化可以首先进行,因为中间步骤没有可观察到的副作用。编译器知道没有办法区分实际构造复杂值和对它们进行操作,只做几个整数操作 - 只要最终结果总是相同的。隐含在“天空中的伟大ObjectIdDict”的概念中假设所有似乎构造的对象实际上都是构造并插入到一个大的永久数据结构中 - 这是一个大量的副作用。因此,不仅从其ID中恢复与垃圾收集不兼容的对象,它还与几乎所有可能的程序优化都不兼容。
可以设想反转object_id
的另一种方法是按需计算其逆图像,而不是在创建对象时保存对象。这将解决内存和优化问题。当然,由于存在无限多个可能的对象但只有有限数量的对象ID,所以不可能。你不太可能在程序中实际遇到两个具有相同ID的对象,但ID空间的有限性意味着反转哈希函数原则 ,因为每个ID值的原像包含一个无限数量的潜在对象。
我可能反驳了反object_id
函数的可能性远远超过必要,但它导致了一些有趣的思想实验,我希望它有所帮助 - 或者至少是发人深思。实际的答案是,没有办法明确地隐藏您可能希望稍后在ObjectIdDict
中找回的每个对象。