一些`Fixnum`属性

时间:2013-03-06 14:40:20

标签: ruby

我在doc中找到了Fixnum的以下功能。

  

Fixnum个对象具有直接价值。这意味着当它们作为参数分配或传递时,将传递实际对象,而不是对该对象的引用。

可以在IRB中显示相同的内容吗?希望只有我能正确地理解它?

  

分配不会为Fixnum对象添加别名。

它究竟是什么呢?

  

对于任何给定的整数值,实际上只有一个Fixnum对象实例,因此,例如,您不能将单例方法添加到Fixnum

无法理解不使用singleton对象实例添加Fixnum方法的原因。

我尝试了第二点如下:

a = 1                      # => 1
a.class                    # => Fixnum
b = a                      # => 1
b.class                    # => Fixnum
a == b                     # => true
a.equal? b                 # => true
a.object_id == b.object_id # => true

但我仍然感到困惑。任何人都可以帮我在这里了解这些功能的核心吗?

2 个答案:

答案 0 :(得分:10)

在Ruby中,大多数对象都需要内存来存储它们的类和实例变量。分配此内存后,Ruby通过此内存位置表示每个对象。将对象分配给变量或传递给函数时,它是传递此内存的位置,而不是此内存中的数据。单身方法利用了这一点。定义单例方法时,Ruby会默默地用新的单例类替换对象类。因为每个对象都存储它的类,所以Ruby可以很容易地用一个实现单例方法的新类替换一个对象的类(并继承自原始类)。

对于具有直接值的对象不再适用:truefalsenil,所有符号以及足够小以适合Fixnum的整数。 Ruby不为这些对象的实例分配内存,它不在内部将对象表示为内存中的位置。相反,它基于其内部表示推断对象的实例。这意味着两个方面:

  1. 每个对象的类不再存储在特定位置的内存中,而是由直接对象的类型隐式确定。这就是Fixnums不能使用单例方法的原因。

  2. 具有相同状态的直接对象(例如,两个整数2378的Fixnum)实际上是相同的实例。这是因为实例是由这种状态决定的。

  3. 为了更好地理解这一点,请考虑在Fixnum上执行以下操作:

    >> x = 3 + 7
    => 10
    >> x.object_id == 10.object_id
    => true
    >> x.object_id == (15-5).object_id
    => true
    

    现在,考虑使用字符串:

    >> x = "a" + "b"
    => "ab"
    >> x.object_id == "ab".object_id
    => false
    >> x.object_id == "Xab"[1...3].object_id
    => false
    >> x == "ab"
    => true
    >> x == "Xab"[1...3]
    => true
    

    Fixnums的对象id相等的原因是它们是具有相同内部表示的直接对象。另一方面,字符串存在于已分配的内存中。每个字符串的对象id是其对象状态在内存中的位置。

    一些低级别信息

    要理解这一点,您必须了解Ruby(至少1.8和1.9)如何在内部处理Fixnums。在Ruby中,所有对象都由C代码中的VALUE类型的变量表示。 Ruby对VALUE

    强加了以下要求
    1. VALUE类型是保存指针的足够大小的最小整数。这意味着,在C中,sizeof(VALUE) == sizeof(void*)

    2. 任何非直接对象必须在4字节边界上对齐。这意味着Ruby分配的任何对象都会为某个整数4*i提供地址i。这也意味着所有指针的两个最低有效位都具有零值。

    3. 第一个要求允许Ruby在类型为VALUE的变量中存储指向对象和立即值的指针。第二个要求允许Ruby根据两个最低有效位检测Fixnum和Symbol对象。

      为了使其更具体,请考虑Ruby对象z的内部二进制表示,我们将在32位体系结构中调用Rz

      MSB                                   LSB
        3           2            1            
       1098 7654 3210 9876 5432 1098 7654 32 10
       XXXX XXXX XXXX XXXX XXXX XXXX XXXX AB CD
      

      Ruby然后解释Rz的表达式z,如下所示:

      1. 如果D==1,则z是Fixnum。此Fixnum的整数值存储在表示的高31位中,并通过执行arithmetic right shift来恢复存储在这些位中的有符号整数来恢复。

      2. 测试了三个特殊表示(全部使用D==0

        • 如果Rz==0,则zfalse
        • 如果Rz==2,则ztrue
        • 如果Rz==4,则znil
      3. 如果ABCD == 1110,则'z'是符号。通过右移八个最低有效位(即C中的z>>8)将符号转换成唯一ID。在32位架构上,这允许2 ^ 24个不同的ID(超过1000万)。在64位体系结构上,这允许2 ^ 48个不同的ID。

      4. 否则,Rz表示内存中Ruby对象实例的地址,z的类型由该位置的类信息确定。

        < / LI>

答案 1 :(得分:0)

嗯...

  1. 这是MRI的内部实施细节。你看,在Ruby中(在C方面),所有Ruby对象都是VALUE。在大多数情况下,VALUE是指向生活在堆栈上的对象的指针。但是直接值(Fixnums,true,false,nil和其他东西)存在于VALUE,其中指向对象的指针通常会存在。
  2. 它使变量成为完全相同的对象。现在,我不知道这是如何在内部工作的,因为它将它分配给VALUE本身,但确实如此。
  3. 因为每次我在程序中使用数字1,我都使用相同的对象。因此,如果我在1上定义单例方法,我的程序中的每个位置,所需的程序等都将具有该单例方法。单例方法通常用于局部monkeypatching。所以,为了防止这种情况,Ruby只是不允许你。