Compartilhar via


Declarações e reatribuções de variáveis

Os valores podem ser associados a símbolos usando as instruções let e mutable. Esses tipos de associações fornecem uma maneira conveniente de acessar um valor por meio do identificador definido. Apesar da terminologia enganosa emprestada de outras linguagens, os identificadores declarados em um escopo local e que contêm valores são chamados variáveis. Isso pode ser enganoso porque as instruções let definem identificadores de atribuição única, que são alças que permanecem associadas ao mesmo valor durante a validade. Variáveis que podem ser vinculadas novamente a valores diferentes em diferentes pontos no código precisam ser explicitamente declaradas como tal e são especificadas usando a instrução mutable.

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

Neste exemplo, a instrução let declara uma variável chamada var1 que não pode ser reatribuída e sempre contém o valor 3. A instrução mutable define uma variável var2 que está temporariamente associada ao valor 3 mas pode ser reatribuída a um valor diferente posteriormente ao usar uma expressão de atribuição, conforme mostrado na última linha. Você pode expressar a mesma instrução com a versão mais curta var2 += 1;, como é comum em outros idiomas. Para obter mais informações, consulte Avaliar e reatribuir instruções.

Para resumir:

  • let é usado para criar uma associação imutável.
  • mutable é usado para criar uma associação mutável.
  • = sem um let é usado para alterar o valor de uma associação mutável.

Para todas as três instruções, o lado esquerdo consiste em um símbolo ou uma tupla de símbolo. Se o lado direito da associação for uma tupla, essa tupla poderá ser totalmente ou parcialmente desconstruída após a atribuição. O único requisito para a desconstrução é que a forma da tupla no lado direito corresponda à forma da tupla de símbolo no lado esquerdo. A tupla de símbolo pode conter tuplas aninhadas ou símbolos omitidos, ou ambos, indicados por um sublinhado. Por exemplo:

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 obter mais informações sobre a desconstrução usando o operador unwrap (!), consulte Acesso de item para tipos de struct.

Todas as atribuições em Q# obedecem às mesmas regras de desconstrução, incluindo, por exemplo, alocações de qubit e atribuições de variável de loop.

Para ambos os tipos de associações, os tipos das variáveis são inferidos do lado direito da associação. O tipo de uma variável sempre permanece o mesmo e uma expressão de atribuição não pode alterá-la. As variáveis locais podem ser declaradas como mutáveis ou imutáveis. Há algumas exceções, como variáveis de loop em loops for, em que o comportamento é predefinido e não pode ser especificado. Os argumentos de função e operação são sempre associados imutavelmente. Em combinação com a falta de tipos de referência, conforme discutido no tópico Imutabilidade, isso significa que uma função ou operação chamada nunca pode alterar nenhum valor no lado do chamador.

Como os estados de Qubit valores não são definidos ou observáveis de dentro de Q#, isso não impede o acúmulo de efeitos colaterais quânticos, que são observáveis apenas por meio de medidas. Para obter mais informações, consulte tipos de dados quantum.

Independentemente de como um valor é associado, os próprios valores são imutáveis. Em particular, isso é verdadeiro para matrizes e itens de matriz. Em contraste com linguagens clássicas populares em que matrizes geralmente são tipos de referência, matrizes em Q# - como todos os tipos - são tipos de valor e sempre imutáveis; ou seja, você não pode modificá-los após a inicialização. Alterar os valores acessados por variáveis de tipo de matriz requer, portanto, construir explicitamente uma nova matriz e reatribuí-la ao mesmo símbolo. Para obter mais informações, consulte expressões de Imutabilidade e Copiar e atualizar expressões.

Instruções Evaluate-and-reassign

Instruções do formulário intValue += 1; são comuns em muitos outros idiomas. Aqui, intValue precisa ser uma variável associada mutavelmente do tipo Int. Essas instruções fornecem uma maneira conveniente de concatenação se o lado direito consiste em aplicar um operador binário e o resultado é rebote para o argumento esquerdo do operador. Por exemplo, este segmento de código

mutable counter = 0;
for i in 1 .. 2 .. 10 {
    counter += 1;
    // ...
}

incrementa o valor do contador counter em cada iteração do loop for e é equivalente a

mutable counter = 0;
for i in 1 .. 2 .. 10 {
    counter = counter + 1;
    // ...
}

Instruções semelhantes existem para uma ampla gama de operadores . Essas expressões de avaliação e reatribução existem para todos os operadores em que o tipo da subexpressão mais à esquerda corresponde ao tipo de expressão. Mais precisamente, eles estão disponíveis para operadores lógicos binários e bit a bit, incluindo deslocamento para a direita e esquerda, expressões aritméticas, incluindo exponencialização e módulo, e concatenações, bem como expressões cópia e atualização.

O exemplo de função a seguir calcula a soma de uma matriz de números 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;
}

Da mesma forma, a função a seguir multiplica cada item em uma matriz com o fator 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 obter mais informações, consulte expressões contextuais, que contém outros exemplos em que as expressões podem ser omitidas em um contexto específico quando uma expressão adequada pode ser inferida pelo compilador.