Declaraciones de variables y reasignaciones
Los valores se pueden enlazar a símbolos mediante las instrucciones let
y mutable
.
Estos tipos de enlaces proporcionan una forma conveniente de acceder a un valor mediante el manipulador definido.
A pesar de la terminología algo engañosa, tomada de otros lenguajes, se llama variables a los manipuladores que se declaran en un ámbito local y que contienen valores.
Esto puede ser engañoso porque las instrucciones let
definen manipuladores de asignación única, que son manipuladores que permanecen enlazados al mismo valor durante la duración de su validez. Las variables que se pueden volver a enlazar a diferentes valores en diferentes puntos del código se tienen que declarar explícitamente como tales y se especifican con la instrucción mutable
.
let var1 = 3;
mutable var2 = 3;
set var2 = var2 + 1;
En este ejemplo, la instrucción let
declara una variable llamada var1
que no se puede reasignar y siempre contiene el valor 3
. La instrucción mutable
define la variable var2
, que está enlazada temporalmente al valor 3
, pero que se puede reasignar a otro valor más adelante con una instrucción set
, como se muestra en la última línea. Puede expresar la misma instrucción con la versión abreviada set var2 += 1;
, que es común en otros lenguajes. Para más información, consulte Instrucciones de evaluación y reasignación.
En resumen:
-
let
se utiliza para crear un enlace inmutable. -
mutable
se utiliza para crear un enlace mutable. -
set
se utiliza para cambiar el valor de un enlace mutable.
Para las tres instrucciones, el lado izquierdo consta de un símbolo o una tupla de símbolos. Si el lado derecho del enlace es una tupla, esa tupla puede ser desconstruida total o parcialmente en la asignación. El único requisito para la desconstrucción es que la forma de la tupla del lado derecho coincida con la forma de la tupla de símbolos del lado izquierdo. La tupla de símbolos puede contener tuplas anidadas o símbolos omitidos, o ambos, indicados por un guión bajo. Por ejemplo:
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]
set (x, _, y) = ((5, 6), 7, [8]); // x is re-bound to (5,6), y is re-bound to [8]
Todas las asignaciones en Q# siguen las mismas reglas de desconstrucción, entre ellas, por ejemplo, las asignaciones de cúbits y las asignaciones de variables de bucle.
Para ambos tipos de enlace, los tipos de las variables se infieren del lado derecho del enlace. El tipo de una variable siempre es el mismo y una instrucción set
no puede cambiarlo.
Las variables locales se pueden declarar como mutables o inmutables. Hay algunas excepciones, como las variables de bucle en los bucles for
, donde el comportamiento está predefinido y no se puede especificar.
Los argumentos de las funciones y las operaciones siempre están enlazados de forma inmutable. En combinación con la falta de tipos de referencia, como se describió en el tema Inmutabilidad, esto significa que una función u operación a la que se llama nunca puede cambiar ningún valor en el lado del autor de llamada.
Ya que los estados de los valores Qubit
no están definidos ni son observables desde dentro de Q#, esto no impide la acumulación de efectos secundarios cuánticos, que solo son observables mediante medidas. Para más información, consulte Tipos de datos cuánticos.
Independientemente de la forma en que se enlaza un valor, los propios valores son inmutables. Específicamente, esto es cierto para matrices y elementos de matriz. A diferencia de los lenguajes clásicos populares, en los que las matrices a menudo son tipos de referencia, las matrices en Q# (como todos los tipos) son tipos de valor y siempre inmutables; es decir, no se pueden modificar después de la inicialización. Para cambiar los valores a los que acceden las variables de tipo matriz, es necesario construir explícitamente una nueva matriz y reasignarla al mismo símbolo. Para más información, consulte Inmutabilidad y Expresiones de copia y actualización.
Instrucciones de evaluación y reasignación
Las instrucciones de la forma son set intValue += 1;
comunes en muchos otros lenguajes. En este caso, intValue
tiene que ser una variable de tipo Int
ligada mutablemente.
Estas instrucciones proporcionan una forma conveniente de concatenación si el lado derecho consiste en la aplicación de un operador binario y el resultado debe ser enlazado de nuevo al argumento izquierdo del operador.
Por ejemplo, este segmento de código
mutable counter = 0;
for i in 1 .. 2 .. 10 {
set counter += 1;
// ...
}
incrementa el valor del contador counter
en cada iteración del bucle for
y es equivalente a
mutable counter = 0;
for i in 1 .. 2 .. 10 {
set counter = counter + 1;
// ...
}
Existen instrucciones similares para una amplia gama de operadores. En estas instrucciones de evaluación y reasignación, la palabra clave set
debe ir seguida de una variable mutable única, que el compilador inserta como la subexpresión más a la izquierda.
Estas instrucciones de evaluación y reasignación existen para todos los operadores en los que el tipo de la subexpresión más a la izquierda coincide con el tipo de la expresión.
De forma más precisa, están disponibles para los operadores binarios lógicos y bit a bit, que incluyen el desplazamiento a la derecha y a la izquierda, para las expresiones aritméticas, entre las que se encuentran la exponenciación y el módulo, para las concatenaciones, así como para las expresiones de copia y actualización.
La siguiente función de ejemplo calcula la suma de una matriz de números de tipo Complex
:
function ComplexSum(values : Complex[]) : Complex {
mutable res = Complex(0., 0.);
for complex in values {
set res w/= Re <- res::Re + complex::Re;
set res w/= Im <- res::Im + complex::Im;
}
return res;
}
De la misma manera, la siguiente función multiplica cada elemento de una matriz con el factor dado:
function Multiplied(factor : Double, array : Double[]) : Double[] {
mutable res = new Double[Length(array)];
for i in IndexRange(res) {
set res w/= i <- factor * array[i];
}
return res;
}
Para más información, consulte Expresiones contextuales y omitidas, que contiene otros ejemplos en los que se pueden omitir las expresiones en un contexto específico cuando el compilador puede inferir una expresión adecuada.