Вопрос

В .NET 4 beta 2 появилось новое пространство имен Numerics с struct BigInteger . документация гласит, что это неизменный тип, как я и ожидал.

Но меня немного смущает оператор постинкремента ( ++ ). Это определенно, кажется, мутирует значение. Работает следующий цикл 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   объект, представленный значением.   Поэтому повторные звонки в инкремент   может быть дорогим.

Все хорошо, я бы понял, если бы мне пришлось использовать 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 ...>

Это оставит в памяти два объекта: исходное значение 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;

После этой операции временная температура утилизируется ГХ, и память освобождается.

BigInteger b = BigInteger.One;

b++;  // immutable ?

В вашем примере b - это переменная, которая представляет собой просто слот памяти в кадре стека текущего метода. Он инициализируется в One, и b ++ берет b, создает новый BigInteger (с увеличенным значением) и возвращает его. переменная b теперь имеет состояние из возвращенного нового BigInteger.

Честно говоря, неизменность концепции как концепции намного яснее при работе со ссылочными типами, поскольку в куче есть объект, внутреннее состояние которого никогда не изменяется, поэтому, когда операция / метод возвращает новый объект с другим состоянием, это становится очевидным (Например, вы можете выполнить проверку равенства ссылок на объекты с помощью object.ReferenceEquals (object, object).

Для типов значений в куче нет объектов, в памяти просто есть слот, содержащий биты, являющиеся значением.

Хорошо, но как насчет унарного оператора отрицания, который определен в BigInteger:

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

кажется, что он нарушает шаблон неизменяемости и напрямую изменяет объект BigInteger. Так

b = -b;

фактически изменяет существующий BigInteger на месте без возврата нового объекта.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top