Déclarations et réaffectations des variables
Les valeurs peuvent être liées à des symboles à l’aide des instructions let
et mutable
.
Ces types de liaisons offrent un moyen pratique d’accéder à une valeur par le biais du descripteur défini.
Malgré la terminologie trompeuse empruntée à d’autres langages, les descripteurs déclarés dans une portée locale et qui contiennent des valeurs sont appelés variables.
Cela peut être trompeur, car les instructions let
définissent des descripteurs à affectation unique, qui sont des descripteurs qui restent liés à la même valeur pendant toute leur durée de validité. Les variables qui peuvent être reliées à des valeurs différentes à d’autres points dans le code doivent être déclarées explicitement comme telles, et sont spécifiées à l’aide de l’instruction mutable
.
let var1 = 3;
mutable var2 = 3;
set var2 = var2 + 1;
Dans cet exemple, l’instruction let
déclare une variable nommée var1
qui ne peut pas être réaffectée et qui contient toujours la valeur 3
. L’instruction mutable
définit une variable var2
liée temporairement à la valeur 3
, mais qui peut être réaffectée à une autre valeur ultérieurement à l’aide d’une instruction set
, comme indiqué dans la dernière ligne. Vous pouvez exprimer la même instruction avec la version plus courte set var2 += 1;
, comme c’est le cas dans d’autres langages. Pour plus d’informations, consultez Évaluer et réaffecter des instructions.
Pour récapituler :
-
let
est utilisé pour créer une liaison immuable. -
mutable
est utilisé pour créer une liaison muable. -
set
est utilisé pour modifier la valeur d’une liaison muable.
Pour les trois instructions, le côté gauche se compose d’un symbole ou d’un tuple de symboles. Si le côté droit de la liaison est un tuple, ce tuple peut être entièrement ou partiellement déconstruit lors de l’affectation. La seule exigence en matière de déconstruction est que la forme du tuple sur le côté droit corresponde à la forme du tuple de symboles sur le côté gauche. Le tuple de symboles peut contenir des tuples imbriqués et/ou des symboles omis, indiqués par un trait de soulignement. Par exemple :
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]
Toutes les affectations dans Q# respectent les mêmes règles de déconstruction, y compris, par exemple, les allocations de qubits et les affectations de variables de boucle.
Pour ces deux types de liaisons, les types des variables sont déduits à partir de la partie droite de la liaison. Le type d’une variable reste toujours le même et une instruction set
ne peut pas modifier cela.
Les variables locales peuvent être déclarées comme mutables ou immuables. Il existe certaines exceptions, telles que les variables de boucle dans les boucles for
, où le comportement est prédéfini et ne peut pas être spécifié.
Les arguments de fonction et d’opération sont toujours liés de façon immuable. En association avec l’absence de types de référence, comme indiqué dans la rubrique sur l’immuabilité, cela signifie qu’une fonction ou une opération appelée ne peut jamais modifier les valeurs du côté de l’appelant.
Comme les états des valeurs Qubit
ne sont pas définis ni observables à partir de Q#, cela n’empêche pas l’accumulation d’effets quantiques secondaires, qui sont observables uniquement par le biais de mesures. Pour plus d’informations, consultez Types de données quantiques.
Indépendamment de la façon dont une valeur est liée, les valeurs elles-mêmes sont immuables. En particulier, cela est vrai pour les tableaux et les éléments de tableau. Contrairement aux langages classiques populaires où les tableaux sont souvent des types de référence, les tableaux, comme tous les types, sont des types de valeurs dans Q# et sont toujours immuables. Ils ne peuvent pas être modifiés après l’initialisation. La modification des valeurs auxquelles accèdent les variables de type tableau nécessite donc explicitement la construction d’un nouveau tableau et sa réaffectation au même symbole. Pour plus d’informations, consultez la section sur l’immuabilité et les expressions de copie et de mise à jour.
Instructions d’évaluation et de réattribution
Les instructions de forme set intValue += 1;
sont courantes dans de nombreux autres langages. Ici, intValue
doit être une variable liée de facon muable de type Int
.
Ces instructions sont un moyen pratique de concaténation si le côté droit est constitué de l’application d’un opérateur binaire et que le résultat doit être relié à l’argument de gauche de l’opérateur.
Par exemple, le segment de code
mutable counter = 0;
for i in 1 .. 2 .. 10 {
set counter += 1;
// ...
}
incrémente la valeur du compteur counter
dans chaque itération de la boucle for
et équivaut à
mutable counter = 0;
for i in 1 .. 2 .. 10 {
set counter = counter + 1;
// ...
}
Des instructions similaires existent pour un large éventail d’opérateurs. Le mot clé set
dans ces instructions d’évaluation et de réattribution doit être suivi d’une seule variable mutable, qui est insérée comme sous-expression la plus à gauche par le compilateur.
Ces instructions Evaluate-and-Reassign existent pour tous les opérateurs où le type de la sous-expression la plus à gauche correspond au type de l’expression.
Plus précisément, elles sont disponibles pour les opérateurs binaires et logiques binaires, y compris le décalage vers la droite et vers la gauche, les expressions arithmétiques, y compris l’élévation à une puissance et le modulo, et les concaténations ainsi que les expressions de copie et de mise à jour.
L’exemple de fonction suivant calcule la somme d’un tableau de nombres 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 même, la fonction suivante multiplie chaque élément dans un tableau par le facteur donné :
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;
}
Pour plus d’informations, consultez la section Expressions contextuelles, qui contient d’autres exemples où les expressions peuvent être omises dans un contexte spécifique lorsqu’une expression appropriée peut être déduite par le compilateur.