Объявления переменных и переназначения
Значения можно привязать к символам с помощью инструкций let
и mutable
.
Эти типы привязок предоставляют удобный способ доступа к значению через определенный дескриптор.
Несмотря на вводящую терминологию, заимствованную с других языков, дескриптор, объявленный в локальной области, и содержащие значения называются переменными.
Это может быть вводя в заблуждение, так как операторы let
определяют дескриптора однозначных дескрипторов, которые остаются привязанными к одному значению в течение срока их действия. Переменные, которые могут быть повторно привязаны к разным значениям в разных точках в коде, необходимо явно объявлять таким образом и указываться с помощью инструкции mutable
.
let var1 = 3;
mutable var2 = 3;
var2 = var2 + 1;
В этом примере инструкция let
объявляет переменную с именем var1
, которая не может быть переназначна и всегда содержит значение 3
. Оператор mutable
определяет переменную var2
, которая временно привязана к значению 3
но может быть переназначен другому значению позже с помощью выражения назначения, как показано в последней строке. Вы можете выразить ту же инструкцию с более короткой версией var2 += 1;
, как и в других языках. Дополнительные сведения см. в разделе Вычисления и переназначение инструкций.
Чтобы свести итоги, выполните приведенные ниже действия.
-
let
используется для создания неизменяемой привязки. -
mutable
используется для создания изменяемой привязки. -
=
безlet
используется для изменения значения изменяемой привязки.
Для всех трех операторов левая сторона состоит из символа или кортежа символов. Если правой стороной привязки является кортеж, этот кортеж может быть полностью или частично деконструенен при назначении. Единственным требованием деконструкции является то, что форма кортежа справа соответствует форме кортежа символа слева. Кортеж символов может содержать вложенные кортежи или опущенные символы или оба символа, указанные символами подчеркивания. Например:
let (a, (_, b)) = (1, (2, 3)); // a is bound to 1, b is bound to 3
mutable (x, y) = ((1, 2), [3, 4]); // x is bound to (1, 2), y is bound to [3, 4]
(x, _, y) = ((5, 6), 7, [8]); // x is re-bound to (5,6), y is re-bound to [8]
Дополнительные сведения о деконструкции с помощью оператора unwrap (!
) см. в разделе Доступ к элементу для типов структур.
Все назначения в Q# подчиняются одинаковым правилам деконструкции, включая, например, выделение кубитов и назначения переменных цикла.
Для обоих видов привязок типы переменных выводятся из правой части привязки. Тип переменной всегда остается неизменным, и выражение назначения не может изменить его.
Локальные переменные можно объявить как изменяемые или неизменяемые. Существуют некоторые исключения, такие как переменные цикла в for
циклах, где поведение предопределено и не может быть указано.
Аргументы функций и операций всегда неизменяемо привязаны. В сочетании с отсутствием ссылочных типов, как описано в разделе неизменяемости, это означает, что вызываемая функция или операция никогда не может изменять любые значения на стороне вызывающего объекта.
Так как состояния Qubit
значений не определены или наблюдаемы из Q#, это не исключает накопление квантовых побочных эффектов, которые можно наблюдать только с помощью измерений. Дополнительные сведения см. в типах данных Quantum.
Независимо от того, как привязано значение, сами значения неизменяемы. В частности, это верно для элементов массивов и массивов. В отличие от популярных классических языков, где массивы часто являются ссылочными типами, массивы в Q# , как и все типы, являются типами значений и всегда неизменяемыми; То есть изменить их после инициализации невозможно. Таким образом, для изменения значений, к которым обращаются переменные типа массива, необходимо явно создать новый массив и переназначить его на тот же символ. Дополнительные сведения см. в неизменяемости и выражений копирования и обновления.
Операторы оценки и переназначение
Операторы формы intValue += 1;
распространены во многих других языках. Здесь intValue
должна быть изменяемой переменной типа Int
.
Такие операторы предоставляют удобный способ объединения, если правая сторона состоит из применения двоичного оператора и результат возвращается к левому аргументу оператора.
Например, этот сегмент кода
mutable counter = 0;
for i in 1 .. 2 .. 10 {
counter += 1;
// ...
}
увеличивает значение счетчика counter
в каждой итерации цикла for
и эквивалентно
mutable counter = 0;
for i in 1 .. 2 .. 10 {
counter = counter + 1;
// ...
}
Аналогичные операторы существуют для широкого диапазона операторов . Такие выражения оценки и переназначения существуют для всех операторов, в которых тип левого подчиненного выражения соответствует типу выражения. Более точно они доступны для двоичных логических и битовых операторов, включая смену вправо и влево, арифметические выражения, включая экспонентацию и модулу, а также сцепления, а также выражения копирования и обновления.
В следующем примере функции вычисляется сумма массива чисел Complex
:
function ComplexSum(values : Complex[]) : Complex {
mutable res = Complex(0., 0.);
for complex in values {
res = new Complex { Re = res.Re + complex.Re, Im = res.Im + complex.Im };
}
return res;
}
Аналогичным образом следующая функция умножает каждый элемент в массиве с заданным коэффициентом:
function Multiplied(factor : Double, array : Double[]) : Double[] {
mutable res = new Double[Length(array)];
for i in IndexRange(res) {
res w/= i <- factor * array[i];
}
return res;
}
Дополнительные сведения см. в контекстных выражений, которые содержат другие примеры, в которых выражения могут быть опущены в определенном контексте, если подходящее выражение может быть выведено компилятором.