代码之家  ›  专栏  ›  技术社区  ›  Henk Holterman

biginteger是否不可变?

  •  9
  • Henk Holterman  · 技术社区  · 15 年前

    在.NET 4 Beta 2中,有一个新的数字名称空间 struct BigInteger . 这个 documentation 声明它是不可变的类型,如我所料。

    但我对后增量运算符有点困惑( ++ )这显然改变了价值。循环工作时,请执行以下操作:

    static BigInteger Factorial(BigInteger n)
    {
        BigInteger result = BigInteger.One;
        BigInteger b = BigInteger.One;
    
        while (b <= n)
        {
            result = result * b;
            b++;  // immutable ?
        }
        return result;
    }
    

    这就是msdn对increment运算符的看法:

    因为biginteger对象是 不可变,递增运算符 创建一个新的BigInteger对象,该对象的 值比BigInteger多一个 由值表示的对象。 因此,重复调用递增 可能很贵。

    一切都很好,如果我不得不使用的话,我会理解的。 b = b++ 但显然 ++ 本身就足以改变一个值。

    有什么想法吗?

    编辑:
    正如拉瑟指出的,有一个 step-by-step specification 关于后增量的工作原理。但这似乎仍然与不可改变性相矛盾。例如,我无法想象使用这个操作符是线程安全的。

    2 回复  |  直到 15 年前
        1
  •  13
  •   Lasse V. Karlsen    15 年前

    算子 ++ -- 是按照正常的 + - 运营商,因此在现实中:

    b++;
    

    相当于:

    var temp = b;
    b = b + 1;
    <use temp for the expression where b++ was located>
    

    现在,正如所评论的,这似乎打破了不变性,但事实并非如此。

    您应该将此代码视为执行此操作:

    var temp = b;
    b = BigInteger.op_Add(b, 1); // constructs a new BigInteger value
    <use temp ...>
    

    这将在内存中保留两个对象,即原始的biginteger值和现在由b引用的新对象。您可以轻松检查以下代码是否会发生这种情况:

    var x = b;
    b++;
    // now inspect the contents of x and b, and you'll notice that they differ
    

    所以原来的对象没有改变,所以它不打破不变性,要回答新的部分的问题,这应该是线程安全的。

    这与字符串发生的情况相同:

    String s1 = s2;
    s2 += "More";
    // now inspect s1 and s2, they will differ
    
        2
  •  3
  •   Ted Lee    15 年前

    由于biginteger是不可变的,因此B++将仅等于:

    BigInteger temp=b;
    b=temp+1;
    

    执行此操作后,GC将回收temp并释放内存。