Wyrażenie defer opóźnia wykonanie kodu do momentu zakończenia bieżącego zakresu. Możesz użyć wyrażenia defer do obsługi zadań czyszczenia, takich jak resetowanie zmiennych. Nawet jeśli nastąpi wcześniejsze wyjście (takie jak return lub break) z bieżącego zakresu, wyrażenia w bloku defer będą działać tak długo, jak długo defer występuje przed wyjściem.
Poniższy kod pokazuje, jak użyć wyrażenia defer do zresetowania zmiennej do zera, jednocześnie używając tej samej zmiennej jako wartości zwrotnej. W tej funkcji zwracana jest wartość RoundScore, a wyrażenia z bloku defer są uruchamiane natychmiast po niej.
Oznacza to, że nie musisz tworzyć zmiennej tymczasowej, aby zapisać wartość RoundScore przed zresetowaniem jej do zera.
OnRoundEnd<public>() : void =
var ScoreThisRound : int = AddRoundScoreToTotalScore()
Print("Points scored this round: {ScoreThisRound}")
<# Adds RoundScore to TotalScore and resets RoundScore to 0.
Returns the RoundScore added. #>
AddRoundScoreToTotalScore<public>() : int =
defer:
set RoundScore = 0
UpdateUI()
Użycie wyrażenia defer
Możesz użyć wyrażenia defer w dowolnym sekwencyjnym bloku kodu, takim jak block, loop, for, if, branch czy nawet inne defer.
Wyrażenia w bloku defer muszą być natychmiastowe (a nie asynchroniczne) – z jednym wyjątkiem. Wyrażenia asynchroniczne mogą być nadal używane w ramach wyrażenia defer, jeśli zostaną ustawione na natychmiastowe za pomocą wyrażeń:
branch(jeślideferznajduje się w bloku asynchronicznym, takim jak współprogram)
Wyrażenie defer nie daje żadnego wyniku i nie może być użyte jako argument ani wartość przypisania.
| defer | defer przed zamknięciem |
|---|---|
Verse | Verse |
Kliknij ilustrację, aby ją powiększyć. | Kliknij ilustrację, aby ją powiększyć. |
Wyrażenie defer zostanie wykonane tylko wtedy, gdy zostanie napotkane zanim nastąpi wcześniejsze wyjście.
| defer z wczesnym wykonaniem wyrażenia return | defer anulowanym asynchronicznym zadaniem |
|---|---|
Verse | Verse |
Kliknij ilustrację, aby ją powiększyć. | Kliknij ilustrację, aby ją powiększyć. |
Jeśli w tym samym zakresie występuje wiele wyrażeń defer, następuje ich akumulacja. Są one wykonywane w kolejności odwrotnej do kolejności ich występowania – "pierwsze weszło, ostatnie wyszło" (FILO). Ostatnie występujące w danym zakresie wyrażenie defer jest wykonywane jako pierwsze, dlatego wyrażenia należące do tego ostatniego wyrażenia defer mogą odnosić się do kontekstu (jak np. zmienne), który zostanie oczyszczony przez inne wyrażenia defer występujące wcześniej, a wykonywane później.
Verse nie obsługuje zniszczenia deterministycznego, ale wyrażenie defer umożliwia uzyskanie zachowania zbliżonego do RAII na potrzeby czyszczenia.
| Wiele wyrażeń defer w jednym bloku kodu | Wiele wyrażeń defer w różnych blokach kodu |
|---|---|
Verse | Verse |
Kliknij ilustrację, aby ją powiększyć. | Kliknij ilustrację, aby ją powiększyć. |
Wcześniejsze wyjście jest dozwolone w ramach bloku defer, o ile wyjście nie powoduje przeniesienia kontroli poza zakres defer. Na przykład użycie pętli z wyrażeniem break jest dozwolone w obrębie defer, ale to break musi utrzymać wykonanie kodu w ramach bloku defer. Nie mogą istnieć odwołania do loop poza blokiem defer.
Wszelkie zmienne, które napotkano w zewnętrznym zakresie zagnieżdżenia wyrażenia defer mogą zostać użyte w tym wyrażeniu defer.
Pamiętaj, że wyrażenie defer jest uruchamiane jako ostatnie w momencie wyjścia z zakresu. Oznacza to, że używa stanu programu (w tym wartości zmiennych) w danym momencie, a nie w momencie napotkania wyrażenia defer. Poniższy kod wyświetli 10, ponieważ wyrażenie defer jest uruchamiane natychmiast po ustawieniu MyScore na 10.
var MyScore = 5
defer:
Print(MyScore)
set MyScore = 10Użycie wyrażenia defer jako ostatniego wyrażenia w zakresie jest równoznaczne z nieużywaniem go w ogóle. Na przykład te dwa zestawy wyrażeń będą uruchamiane dokładnie w tej samej kolejności, więc wyrażenie defer nie jest potrzebne:
| Bez wyrażenia defer | Z wyrażeniem defer |
|---|---|
Verse | Verse |