BigIntegerは不変ですか?
-
06-07-2019 - |
質問
.NET 4ベータ2には、 struct BigInteger
を持つ新しいNumerics名前空間があります。 ドキュメントには、私が期待していたように、それは不変の型です。
しかし、ポストインクリメント演算子( ++
)に少し混乱しています。これは間違いなく値を変化させるようです。次のwhileループが機能します。
static BigInteger Factorial(BigInteger n)
{
BigInteger result = BigInteger.One;
BigInteger b = BigInteger.One;
while (b <= n)
{
result = result * b;
b++; // immutable ?
}
return result;
}
これは、増分演算子についてMSDNが言っていることです:
BigIntegerオブジェクトは 不変、インクリメント演算子 その新しいBigIntegerオブジェクトを作成します 値はBigIntegerよりも1つ大きい 値で表されるオブジェクト。 したがって、Incrementの繰り返し呼び出し 高価かもしれません。
すべて問題なく、 b = b ++
を使用する必要がある場合は理解できたはずですが、値を変更するには ++
だけで十分です。
何か考えはありますか
解決
演算子 ++
および-
は、通常の +
および-
演算子の観点から実装されています。現実には:
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 ...>
これにより、2つのオブジェクト、元の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
他のヒント
BigIntegerは不変であるため、b ++は次のものと同等になります。
BigInteger temp=b;
b=temp+1;
この操作の後、tempはGCによってリサイクルされ、メモリが解放されます。
BigInteger b = BigInteger.One;
b++; // immutable ?
例では、bは変数であり、現在のメソッドのスタックフレーム内のメモリのスロットにすぎません。これはOneに初期化され、b ++はbを取り、新しいBigIntegerを作成し(増分された値で)、それを返します。変数bは、返された新しいBigIntegerからの状態になります。
参照状態を処理する場合、内部状態が変化しないオブジェクトがヒープ上にあるため、概念としての不変性は正直に言うと、操作/メソッドが異なる状態の新しいオブジェクトを返すとき、それは一種の明らかです(たとえば、object.ReferenceEquals(object、object)を使用してオブジェクト参照の等価性チェックを実行できます。
値型の場合、ヒープ上にオブジェクトはなく、値であるビットを含むメモリ内のスロットのみがあります。
OK、しかしBigIntegerで定義されている単項否定演算子はどうですか:
public static BigInteger operator -(BigInteger value)
{
value._sign = -value._sign;
return value;
}
不変性パターンを破り、BigIntegerオブジェクトを直接変異させるようです。だから
b = -b;
新しいオブジェクトを返すことなく、既存のBigIntegerを実際に変更します。