Variabeldeklarationer och omtilldelningar
Värden kan bindas till symboler med hjälp av let
- och mutable
-instruktioner.
Den här typen av bindningar är ett bekvämt sätt att komma åt ett värde via det definierade handtaget.
Trots den vilseledande terminologi som lånats från andra språk kallas referenser som deklarerats i ett lokalt omfång och innehåller värden variabler.
Detta kan vara missvisande eftersom let
-instruktioner definierar entilldelningsreferenser, som är referenser som förblir bundna till samma värde under varaktigheten av deras giltighet. Variabler som kan bindas om till olika värden vid olika tidpunkter i koden måste uttryckligen deklareras som sådana och anges med hjälp av mutable
-instruktionen.
let var1 = 3;
mutable var2 = 3;
var2 = var2 + 1;
I det här exemplet deklarerar let
-instruktionen en variabel med namnet var1
som inte kan omtilldelas och alltid innehåller värdet 3
.
mutable
-instruktionen definierar en variabel var2
som tillfälligt är bunden till värdet 3
men som kan tilldelas till ett annat värde senare med hjälp av ett tilldelningsuttryck, som visas på den sista raden. Du kan uttrycka samma instruktion med den kortare versionen var2 += 1;
, som är vanligt på andra språk. Mer information finns i Utvärdera och omtilldela instruktioner.
Sammanfatta:
-
let
används för att skapa en oföränderlig bindning. -
mutable
används för att skapa en föränderlig bindning. -
=
utanlet
används för att ändra värdet för en föränderlig bindning.
För alla tre uttrycken består den vänstra sidan av en symbol eller en symboltupppel. Om bindningens högra sida är en tuppeln kan tuppeln helt eller delvis dekonstrueras vid tilldelningen. Det enda kravet för dekonstruktion är att tuppelns form på höger sida matchar formen på symboltuppeln till vänster. Symboltuppeln kan innehålla kapslade tupplar eller utelämnade symboler, eller båda, som indikeras av ett understreck. Till exempel:
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]
Mer information om dekonstruktion med operatorn unwrap (!
) finns i Item access for struct types.
Alla tilldelningar i Q# följa samma dekonstruktionsregler, till exempel kvantbitsallokeringar och loopvariabeltilldelningar.
För båda typerna av bindningar härleds variablernas typer från den högra sidan av bindningen. Typen av variabel förblir alltid densamma och ett tilldelningsuttryck kan inte ändra den.
Lokala variabler kan deklareras som antingen föränderliga eller oföränderliga. Det finns vissa undantag, till exempel loopvariabler i for
-loopar, där beteendet är fördefinierat och inte kan anges.
Funktions- och åtgärdsargument är alltid oföränderligt bundna. I kombination med bristen på referenstyper, som beskrivs i avsnittet Oföränderlighet, innebär det att en så kallad funktion eller åtgärd aldrig kan ändra några värden på anroparsidan.
Eftersom tillstånden för Qubit
värden inte definieras eller kan observeras inifrån Q#utesluter detta inte ackumulering av kvant sidoeffekter, som endast kan observeras via mätningar. Mer information finns i Kvantdatatyper.
Oberoende av hur ett värde är bundet är själva värdena oföränderliga. Detta gäller särskilt för matriser och matrisobjekt. Till skillnad från populära klassiska språk där matriser ofta är referenstyper är matriser i Q# , som alla typer, värdetyper och alltid oföränderliga. Du kan alltså inte ändra dem efter initieringen. Om du ändrar de värden som används av variabler av matristyp måste du därför uttryckligen konstruera en ny matris och tilldela om den till samma symbol. Mer information finns i Oföränderlighet och Kopiera och uppdatera uttryck.
Utvärdera och omtilldela instruktioner
Instruktioner för formuläret intValue += 1;
är vanliga på många andra språk. Här måste intValue
vara en föränderligt bunden variabel av typen Int
.
Sådana instruktioner ger ett bekvämt sätt att sammanfoga om den högra sidan består av att tillämpa en binär operator och resultatet återgår till operatorns vänstra argument.
Till exempel det här kodsegmentet
mutable counter = 0;
for i in 1 .. 2 .. 10 {
counter += 1;
// ...
}
ökar värdet för räknaren counter
i varje iteration av for
-loopen och motsvarar
mutable counter = 0;
for i in 1 .. 2 .. 10 {
counter = counter + 1;
// ...
}
Liknande instruktioner finns för en mängd olika operatorer. Sådana utvärderings- och omtilldelningsuttryck finns för alla operatorer där typen av det vänstra underuttrycket matchar uttryckstypen. Mer exakt, de är tillgängliga för binära logiska och bitvis operatorer inklusive höger och vänster skift, aritmetiska uttryck inklusive exponentiation och modulus, och sammanfogningar, samt kopiera och uppdatera uttryck.
I följande funktionsexempel beräknas summan av en matris med Complex
tal:
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;
}
På samma sätt multiplicerar följande funktion varje objekt i en matris med den angivna faktorn:
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;
}
Mer information finns i Kontextuella uttryck, som innehåller andra exempel där uttryck kan utelämnas i en specifik kontext när ett lämpligt uttryck kan härledas av kompilatorn.