defer 式 は、現在の スコープ を終了するまでコードの実行を遅らせることができます。defer 式を使用すると、変数 のリセットなどのクリーンアップ タスクを処理することができます。現在のスコープを早い段階で終了する場合 (return または break など) でも、defer ブロック内の式は、終了する前に defer が検出される限り実行されます。
次のコードは、defer を使用して変数をゼロにリセットしながら、その変数を return 値として使用する方法を示しています。この 関数 では、RoundScore が返され、その直後に defer ブロック内の式が実行されます。
つまり、ゼロにリセットされる前に、RoundScore の値を保存するための一時的な変数を作成する必要はありません。
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()
set TotalScore += RoundScore
return RoundScore
defer 式の使用方法
defer 式は、block、loop、for、if、branch など、任意のシーケンシャル コード ブロック 内、または他の defer でも使用することができます。
defer ブロック内の式は、(非同期 式ではなく) 即時 式である必要があります。ただし、例外が 1 つあります。非同期式でも、以下を使用してその式を即時式にした場合は、defer 内で使用できます。
- spawn
branch(deferがコルーチン内にあるなど非同期ブロック内にある場合)
defer は結果がないため、引数や代入値として使用することはできません。
| defer | 終了する前に defer |
|---|---|
|
|
画像をクリックすると拡大表示されます。 |
画像をクリックすると拡大表示されます。 |
defer 式は、早期に終了する前に検出された場合のみ実行されます。
| 早期に戻り値が得られる場合の defer | 非同期式がキャンセルされた場合の defer |
|---|---|
|
|
画像をクリックすると拡大表示されます。 |
画像をクリックすると拡大表示されます。 |
同じスコープに出現する複数の defer 式は累積されます。それらが実行される順序は、検出された逆の順序、つまり先入れ後出し (FILO) 順です。特定のスコープ内で最後に検出された defer が最初に実行されるため、その最後に検出された defer の内部にある式は、以前に検出され、後に実行された他の defer 式によってクリーンアップされるコンテキスト (変数など) を参照できます。
Verse には 決定論的デストラクション はありませんが、defer を使用すると RAII と同様の動作でクリーンアップを確実に行うことができます。
| コード ブロック内の複数の defer 式 | 異なるコード ブロック内の複数の defer 式 |
|---|---|
|
|
画像をクリックすると拡大表示されます。 |
画像をクリックすると拡大表示されます。 |
defer ブロック内での早期終了は、その終了が defer のスコープ外に制御を転送しない限り許可されます。たとえば、ループを break と併用することは defer 内では可能であるものの、break でコードの実行が defer ブロック内で保持されている必要があります。defer ブロック外から loop を参照することはできません。
defer の外側で ネスティング スコープで検出されたすべての変数は、その defer 式内で使用することができます。
なお、defer は、スコープの終了時の最後に実行されます。つまり、defer の検出時ではなく、その時点のプログラムの状態 (変数の値を含む) を問わず、defer が使用されます。以下のコードでは、10 が出力されます。これは、defer が、MyScore が 10 に設定された直後に実行されるためです。
var MyScore = 5
defer:
Print(MyScore)
set MyScore = 10
defer 式をスコープ内の最後の式として使用することは、その式をまったく使用しないことと同じになります。たとえば、これら 2 組の式はまったく同じ順序で実行されるため、defer は必要ありません。
| defer なし | defer あり |
|---|---|
|
|