BigInteger是不可变的吗?

问题描述 投票:9回答:4

在.NET 4 beta 2中,有一个新的Numerics命名空间和struct BigIntegerdocumentation表示它是一种不可改变的类型,正如我所料。

但我对后增量算子(qazxsw poi)有点困惑。这肯定似乎改变了价值。以下while循环有效:

++

这就是MSDN对Increment运算符的看法:

因为BigInteger对象是不可变的,所以Increment运算符创建一个新的BigInteger对象,其值比value表示的BigInteger对象多一个。因此,重复调用Increment可能很昂贵。

一切都很好,我会理解,如果我必须使用static BigInteger Factorial(BigInteger n) { BigInteger result = BigInteger.One; BigInteger b = BigInteger.One; while (b <= n) { result = result * b; b++; // immutable ? } return result; } 但显然b = b++本身足以改变一个值。

有什么想法吗?

c# .net immutability biginteger fcl
4个回答
14
投票

运算符++++是根据正常的--+运算符实现的,所以实际上:

-

相当于:

b++;

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

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

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

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

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

所以原始对象没有改变,因此它不会破坏不变性,并且回答问题的新部分,这应该是线程安全的。

这与字符串相同:

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

3
投票

由于BigInteger是不可变的,因此b ++将等同于:

String s1 = s2;
s2 += "More";
// now inspect s1 and s2, they will differ

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


0
投票
BigInteger temp=b;
b=temp+1;

在你的例子中,b是一个变量,它只是当前方法堆栈帧中的一个内存槽。它被初始化为One,b ++接受b,创建一个新的BigInteger(具有递增的值)并返回它。变量b现在具有返回的新BigInteger的状态。

说实话,作为一个概念的不变性在处理引用类型时要清楚得多,因为堆上有一个对象,其内部状态永远不会改变,所以当一个操作/方法返回一个具有不同状态的新对象时,它是显而易见的(例如你可以使用object.ReferenceEquals(object,object)进行对象引用相等性检查。

对于值类型,堆上没有对象,内存中只有包含值的位。


-1
投票

好的,但是在BigInteger上定义的一元否定运算符呢:

BigInteger b = BigInteger.One;

b++;  // immutable ?

它似乎打破了不变性模式并直接改变了BigInteger对象。所以

public static BigInteger operator -(BigInteger value)
{
    value._sign = -value._sign;
    return value;
}

实际上,在不返回新对象的情况下更改现有BigInteger。

© www.soinside.com 2019 - 2024. All rights reserved.