Compartir a través de


Declaraciones y reasignaciones de variables

Los valores se pueden enlazar a símbolos mediante las instrucciones let y mutable. Estos tipos de enlaces proporcionan una manera cómoda de acceder a un valor a través del identificador definido. A pesar de la terminología engañosa tomada de otros lenguajes, los identificadores declarados en un ámbito local y los valores que contienen se denominan variables . Esto puede ser engañoso porque let instrucciones definen identificadores de asignación única, que son identificadores que permanecen enlazados al mismo valor durante la duración de su validez. Las variables que se pueden volver a enlazar a valores diferentes en distintos puntos del código deben declararse explícitamente como tal y se especifican mediante la instrucción mutable.

    let var1 = 3; 
    mutable var2 = 3; 
    var2 = var2 + 1; 

En este ejemplo, la instrucción let declara una variable denominada var1 que no se puede reasignar y siempre contiene el valor 3. La instrucción mutable define una variable var2 que está enlazada temporalmente al valor 3, pero que se puede reasignar a un valor diferente más adelante mediante una expresión de asignación, como se muestra en la última línea. Puede expresar la misma instrucción con la versión más corta var2 += 1;, como es habitual en otros idiomas. Para obtener más información, vea Evaluar y reasignar instrucciones.

Para resumir:

  • let se usa para crear un enlace inmutable.
  • mutable se usa para crear un enlace mutable.
  • = sin un let se usa 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 totalmente o parcialmente deconstruida tras la asignación. El único requisito de deconstrucción es que la forma de la tupla en el lado derecho coincide con la forma de la tupla de símbolos en el lado izquierdo. La tupla de símbolos puede contener tuplas anidadas o símbolos omitidos, o ambos, indicados por un carácter de subrayado. 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]
(x, _, y) = ((5, 6), 7, [8]);  // x is re-bound to (5,6), y is re-bound to [8]

Para obtener más información sobre la deconstrucción mediante el operador unwrap (!), vea Acceso a elementos para tipos de estructura.

Todas las asignaciones de Q# obedecer las mismas reglas de deconstrucción, incluidas, por ejemplo, asignaciones de cúbits y asignaciones de variables de bucle.

Para ambos tipos de enlaces, los tipos de las variables se deducen del lado derecho del enlace. El tipo de una variable siempre sigue siendo el mismo y una expresión de asignación no puede cambiarla. Las variables locales se pueden declarar como mutables o inmutables. Hay algunas excepciones, como las variables de bucle en for bucles, donde el comportamiento está predefinido y no se puede especificar. Los argumentos de función y operación siempre están enlazados inmutablemente. En combinación con la falta de tipos de referencia, como se describe en el tema Inmutability, esto significa que una función o operación denominada nunca puede cambiar ningún valor en el lado del autor de la llamada.

Dado que los estados de Qubit valores no están definidos ni observables desde dentro de Q#, esto no impide la acumulación de efectos secundarios cuánticos, que solo son observables a través de medidas. Para obtener más información, consulte tipos de datos cuánticos.

Independientemente de cómo se enlaza un valor, los propios valores son inmutables. En concreto, esto es cierto para matrices y elementos de matriz. A diferencia de los lenguajes clásicos populares en los que las matrices suelen ser tipos de referencia, matrices en Q# , como todos los tipos, son tipos de valor e inmutables siempre; es decir, no se pueden modificar después de la inicialización. El cambio de los valores a los que acceden las variables de tipo matriz requiere construir explícitamente una nueva matriz y reasignarla al mismo símbolo. Para obtener más información, vea de inmutabilidad y expresiones de copia y actualización.

Instrucciones Evaluate-and-reassign

Las instrucciones de la forma intValue += 1; son comunes en muchos otros lenguajes. Aquí, intValue debe ser una variable enlazada inmutablemente de tipo Int. Estas instrucciones proporcionan una forma cómoda de concatenación si el lado derecho consiste en aplicar un operador binario y el resultado se vuelve a enlazar al argumento izquierdo del operador. Por ejemplo, este segmento de código

mutable counter = 0;
for i in 1 .. 2 .. 10 {
    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 {
    counter = counter + 1;
    // ...
}

Existen instrucciones similares para una amplia gama de operadores de . Estas expresiones evaluate-and-reassign existen para todos los operadores en los que el tipo de subexpresión de la izquierda coincide con el tipo de expresión. De forma más precisa, están disponibles para operadores binarios lógicos y bit a bit, como desplazamiento derecho e izquierdo, expresiones aritméticas, como exponente y módulo, y concatenaciones, así como expresiones copy-and-update expresiones de copia y actualización.

En el ejemplo de función siguiente se calcula la suma de una matriz de números de 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;
}

De forma similar, la función siguiente multiplica cada elemento de una matriz con el factor especificado:

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;
}

Para obtener más información, vea expresiones contextuales, que contiene otros ejemplos en los que se pueden omitir expresiones en un contexto específico cuando el compilador puede inferir una expresión adecuada.