Id2sym&symbol.object_id

使用ruby-hacking-guide网站 ,我发现fixnum << 8 | 1 fixnum << 8 | 1是任何fixnum的object_id。
我尝试过使用符号的类似方法。

#define ID2SYM(x) ((VALUE)(((long)(x))<<8|SYMBOL_FLAG))

当向左移8位时, x变为256的倍数,这意味着4的倍数。然后按位或(在这种情况下,它与添加相同)与0×0e (十进制14)

我尝试过:a:a.object_id = 175_976,在我的32位系统上):

  1. a的ASCII码是97。
  2. 97 << 8 = 24832
  3. 24832 | 14 = 24_846

所以它甚至不接近:a对象id。

我检查了object_id来源,发现了这个:

  * sizeof(RVALUE) is * 20 if 32-bit, double is 4-byte aligned * 24 if 32-bit, double is 8-byte aligned * 40 if 64-bit */ if (SYMBOL_P(obj)) { return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG; 

我得到~50万,这是不好的价值。

那么我错过了什么? 如何计算符号的object_id?

您从符号object_id计算的ID值不直接表示该符号的字符串内容。 它是Ruby维护包含字符串的表的索引。 当你在Ruby中使用一个符号时,如果在当前进程中之前没有使用过该符号,它将被赋予符号表中下一个空闲槽的ID值。

这意味着给定的符号并不总是具有相同的ID值。 与Ruby进程符号关联的ID值将取决于它们的创建顺序。

您可以通过启动新的Ruby进程,创建新符号并查看其object_id ,然后使用不同的符号名称重复来看到这一点。 在两种情况下, object_id应该相同,因为它将引用符号表中的下一个空闲点。 你需要小心这样做,因为Ruby自己定义了很多符号,所以如果你使用其中一个符号,你会得到不同的结果。

例如, irb会话:

 2.1.0 :001 > Symbol.all_symbols.find {|sym| sym.to_s == 'matt' } => nil 2.1.0 :002 > :matt.object_id => 542248 

而另一个:

 2.1.0 :001 > Symbol.all_symbols.find {|sym| sym.to_s == 'banana' } => nil 2.1.0 :002 > :banana.object_id => 542248 

这里我们首先检查我们要使用的名称是否已经作为符号存在,然后我们创建符号并查看其object_id 。 在这两种情况下,它都是相同的542248 ,对应于ID 2118,即使它们具有不同的名称(这些值在不同的系统或Ruby版本上可能不同)。