Deklarace proměnných a opětovné přiřazení
Hodnoty mohou být vázány na symboly pomocí let
a mutable
příkazů.
Tyto druhy vazeb poskytují pohodlný způsob, jak získat přístup k hodnotě prostřednictvím definovaného popisovače.
Navzdory zavádějící terminologii vypůjčené z jiných jazyků se obslužné rutiny deklarované v místním oboru a obsahující hodnoty nazývají proměnné.
To může být zavádějící, protože let
příkazy definují zpracování jedno přiřazení, což jsou popisovače, které zůstávají vázané na stejnou hodnotu po dobu jejich platnosti. Proměnné, které je možné znovu vázat na různé hodnoty v různých bodech kódu, musí být explicitně deklarovány jako takové a jsou určeny pomocí příkazu mutable
.
let var1 = 3;
mutable var2 = 3;
var2 = var2 + 1;
V tomto příkladu příkaz let
deklaruje proměnnou s názvem var1
, která nemůže být znovu přiřazena a vždy obsahuje hodnotu 3
. Příkaz mutable
definuje proměnnou var2
, která je dočasně svázaná s hodnotou 3
, ale později ji můžete znovu přiřadit k jiné hodnotě pomocí výrazu přiřazení, jak je znázorněno na posledním řádku. Stejný příkaz můžete vyjádřit s kratší verzí var2 += 1;
, jak je běžné v jiných jazycích. Další informace naleznete v tématu Vyhodnocení a opětovné přiřazení příkazů.
Shrnutí:
-
let
slouží k vytvoření neměnné vazby. -
mutable
slouží k vytvoření proměnlivé vazby. -
=
bezlet
se používá ke změně hodnoty proměnlivé vazby.
U všech tří příkazů se levá strana skládá ze symbolu nebo řazené kolekce členů symbolu. Pokud je pravá strana vazby řazenou kolekcí členů, může být tato řazená kolekce členů při přiřazení zcela nebo částečně zkonstruována. Jediným požadavkem pro dekonstrukci je, že tvar řazené kolekce členů na pravé straně odpovídá tvaru řazené kolekce členů symbolu na levé straně. Řazená kolekce členů symbolu může obsahovat vnořené řazené kolekce členů nebo vynechané symboly nebo obojí označené podtržítkem. Například:
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]
Další informace o dekonstrukci pomocí unwrap (!
) operátor, naleznete v tématu Item access for struct types.
Všechna přiřazení v Q# dodržují stejná pravidla dekonstrukce, včetně například přidělení qubitů a přiřazení proměnných smyčky.
U obou typů vazeb se typy proměnných odvozují z pravé strany vazby. Typ proměnné zůstane vždy stejný a výraz přiřazení ho nemůže změnit.
Místní proměnné lze deklarovat jako proměnlivé nebo neměnné. Existují některé výjimky, jako jsou proměnné smyčky ve smyčce for
, kde je chování předdefinované a nelze je zadat.
Argumenty funkce a operace jsou vždy neměnně vázané. V kombinaci s chybějícími odkazovými typy, jak je popsáno v Immutability tématu, to znamená, že volaná funkce nebo operace nemůže nikdy změnit žádné hodnoty na straně volajícího.
Vzhledem k tomu, že stavy Qubit
hodnot nejsou definovány nebo pozorovatelné z Q#, nebrání tomu akumulace kvantových vedlejších účinků, které jsou pozorovatelné pouze prostřednictvím měření. Další informace najdete v tématu kvantových datových typů.
Nezávisle na tom, jak je hodnota vázána, jsou samotné hodnoty neměnné. Konkrétně platí pro pole a položky pole. Na rozdíl od oblíbených klasických jazyků, kde jsou pole často referenčními typy, pole v Q# – stejně jako všechny typy – jsou typy hodnot a vždy neměnné; to znamená, že po inicializaci je nelze upravit. Změna hodnot přístupných proměnnými typu pole proto vyžaduje explicitní vytvoření nového pole a jeho opětovné přiřazení ke stejnému symbolu. Další informace naleznete v tématu Neměnnost a Kopírovat a aktualizovat výrazy.
Příkazy Evaluate-and-reassign
Příkazy formuláře intValue += 1;
jsou běžné v mnoha dalších jazycích. Tady musí být intValue
proměnlivou proměnnou typu Int
.
Tyto příkazy poskytují pohodlný způsob zřetězení, pokud se pravá strana skládá z použití binárního operátoru a výsledek se přepoje na levý argument operátoru.
Například tento segment kódu
mutable counter = 0;
for i in 1 .. 2 .. 10 {
counter += 1;
// ...
}
zvýší hodnotu čítače counter
v každé iteraci smyčky for
a odpovídá
mutable counter = 0;
for i in 1 .. 2 .. 10 {
counter = counter + 1;
// ...
}
Podobné příkazy existují pro širokou škálu operátorů . Takové výrazy evaluate-and-reassign existují pro všechny operátory, kde typ sub-výrazu nejvíce vlevo odpovídá typu výrazu. Přesněji řečeno, jsou k dispozici pro binární logické a bitové operátory, včetně pravého a levého posunu, aritmetických výrazů včetně exponentace a modulu a zřetězení a také výrazy kopírování a aktualizace.
Následující příklad funkce vypočítá součet pole Complex
čísel:
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;
}
Podobně následující funkce vynásobí každou položku v matici daným faktorem:
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;
}
Další informace najdete v tématu Kontextové výrazy, které obsahují další příklady, ve kterých lze výrazy vynechat v konkrétním kontextu, pokud je možné odvodit vhodný výraz kompilátorem.