Wyrażenia kontekstowe i pominięte
Wyrażenia kontekstowe to wyrażenia, które są prawidłowe tylko w niektórych kontekstach, takich jak użycie nazw elementów w wyrażeniach kopiowania i aktualizacji bez konieczności ich kwalifikowania.
Wyrażenia można pominąć, gdy można je wywnioskować i automatycznie wstawić przez kompilator, na przykład instrukcje evaluate-and-reassign.
Zakresy otwarte to kolejny przykład, który ma zastosowanie zarówno do wyrażeń kontekstowych, jak i pominiętych. Są one prawidłowe tylko w określonym kontekście, a kompilator tłumaczy je na normalne wyrażenia Range
podczas kompilacji, wnioskowając odpowiednie granice.
Wartość typu Range
generuje sekwencję liczb całkowitych określoną przez wartość początkową, wartość kroku (opcjonalnie) i wartość końcową. Na przykład wyrażenie literału Range
1..3
generuje sekwencję 1,2,3. Podobnie wyrażenie 3..-1..1
generuje sekwencję 3,2,1. Za pomocą zakresów można również utworzyć nową tablicę na podstawie istniejącej, na przykład fragmentując:
let arr = [1,2,3,4];
let slice1 = arr[1..2..4]; // contains [2,4]
let slice2 = arr[2..-1..0]; // contains [3,2,1]
Nie można zdefiniować nieskończonego zakresu w Q#; wartości początkowe i końcowe muszą być zawsze określone. Jedynym wyjątkiem jest użycie Range
do wycinków tablicy. W takim przypadku kompilator może rozsądnie wywnioskować wartości początkowe lub końcowe zakresu.
W poprzednich przykładach fragmentowania tablicy uzasadnione jest założenie, że docelowy koniec zakresu powinien być indeksem ostatniego elementu w tablicy, jeśli rozmiar kroku jest dodatni. Jeśli rozmiar kroku jest ujemny, prawdopodobnie koniec zakresu powinien być indeksem pierwszego elementu w tablicy, 0
. Odwrotność zawiera początek zakresu.
Podsumowując, jeśli pominięto wartość początkową zakresu, wnioskowana wartość początkowa
- jest zero, jeśli nie określono żadnego kroku lub określony krok jest dodatni.
- jest długością tablicy minus jeden, jeśli określony krok jest ujemny.
Jeśli pominięto wartość końcową zakresu, wnioskowana wartość końcowa
- jest długością tablicy minus jeden, jeśli nie określono żadnego kroku lub określony krok jest dodatni.
- wartość zero, jeśli określony krok jest ujemny.
Q# z tego względu umożliwia korzystanie z zakresów otwartych w wyrażeniach fragmentowania tablicy, na przykład:
let arr = [1,2,3,4,5,6];
let slice1 = arr[3...]; // slice1 is [4,5,6];
let slice2 = arr[0..2...]; // slice2 is [1,3,5];
let slice3 = arr[...2]; // slice3 is [1,2,3];
let slice4 = arr[...2..3]; // slice4 is [1,3];
let slice5 = arr[...2...]; // slice5 is [1,3,5];
let slice7 = arr[4..-2...]; // slice7 is [5,3,1];
let slice8 = arr[...-1..3]; // slice8 is [6,5,4];
let slice9 = arr[...-1...]; // slice9 is [6,5,4,3,2,1];
let slice10 = arr[...]; // slice10 is [1,2,3,4,5,6];
Ponieważ określenie, czy krok zakresu jest pozytywny, czy ujemny występuje w czasie wykonywania, kompilator wstawia odpowiednie wyrażenie, które jest oceniane w czasie wykonywania. W przypadku pominiętych wartości końcowych wstawione wyrażenie jest step < 0 ? 0 | Length(arr)-1
, a dla pominiętych wartości początkowych jest step < 0 ? Length(arr)-1 | 0
, gdzie step
jest wyrażeniem podanym dla kroku zakresu lub 1
, jeśli nie określono żadnego kroku.