GoSub、On...GoSub、Return ステートメントを使用して同一プロシージャ内で制御を移す

分岐ステートメントの GoSub と On...GoSub は、使い方の限られたプログラミングテクニックです。同一プロシージャ内の任意の位置 (複数可) から制御を移すことにより、ステートメントグループを実行できます。機能的にはステートメントはサブルーチンのように動作しますが、引数をとることや、別のスコープの設定はできず、他のプロシージャやスクリプトから使用できません。通常のサブルーチンとしてステートメントを記述するほうがより一般的であり、便利です。

構文は次のとおりです。

GoSub label

On expression GoSub label [ , label ]...

Return

ステートメント GoSub label はラベル label の付いたステートメントに制御を移し、label で始まるステートメントから実行を開始し、次のどれかが発生するまで実行を続けます。

ラベル付きステートメントの後で Return ステートメントの前に実行されるステートメントグループは、その他の制御の移動も含めて、現在のプロシージャ内のサブルーチンとして動作します。

ステートメント On expression GoSub label, label, ... も GoSub label と同様に制御を移しますが、ジャンプ先のラベルが expression の値に基づいて決まる点が異なります。つまり、expression が 1 であれば最初の label へ、expression が 2 であれば、2 番目の label へ、というように制御が移ります。 (これらのラベルが同じであっても構いません)。Return ステートメントは On...GoSub の次のステートメントに制御を戻します。

プロシージャ内の GoSub ステートメントの位置は、制御が移される先のラベル付きステートメントの位置とは関係ありません。必要なのは、GoSub とそのジャンプ先のラベル付きステートメントが同一プロシージャ内に存在する必要がある、ということのみです。実際の制御のフローは実行時に決まります。

GoSub または On...GoSub ステートメントを実行すると、戻り位置が定義されます。Return ステートメントが実行される前に別の GoSub または On...GoSub が実行されることもあります。Return ステートメントが実行されると、最後に定義された戻り位置に制御が戻されます。その後、その戻り位置の定義は解除されます。

Return ステートメントはプロシージャからは戻りません。プロシージャ内に現在戻り位置がない場合に Return ステートメントを実行しようとすると、ランタイムエラーになります。

これらのステートメントは、戻り点位置を設定しないで制御を移す GoTo や On...GoTo ステートメントとは異なります。

次の例では、On...GoSub を使用して、LotusScript® 言語の 2 つの単純なパフォーマンステストのどちらかを実行します。入力ボックスに 1 か 2 を入力することにより、Do ループの 1000 回繰り返しの時間測定と、1 秒間に実行される Yield ステートメント数のカウントのどちらかをユーザーが選択します。スクリプトは On...GoSub を使用して選択されたテストへ分岐して実行します。1 つの Print ステートメントで結果を表示します。

Sub RunPerfTest
   Dim directTempV As Variant, directTest As Integer, i As Integer
   Dim startTime As Single, measure As Single, idPace As String
   SpecTest: directTempV = InputBox$ _
     (|Type 1 for iteration time, or 2 for # of yields:|)
   If Not IsNumeric(directTempV) Then Exit Sub
   directTest% = CInt(directTempV)
   If directTest% < 1 Or directTest% > 2 Then _
     Beep : GoTo SpecTest
   i% = 0
   ' Branch on 1 or 2.
   On directTest% GoSub TimeCheck, ItersCheck
   ' Return here to print the performance-test result,
   ' and leave.
   Print idPace$ measure!
   Exit Sub
TimeCheck:
   startTime! = Timer()
   Do While i% <= 1000
      i% = i% + 1
   Loop
   measure! = Timer() - startTime!
   idPace$ = "Time in seconds for 1000 Do iterations: "
   Return
ItersCheck:
   startTime! = Timer()
   Do While Timer() < startTime! + 1
      Yield
      i% = i% + 1
   Loop
   measure! = i%
   idPace$ = "Number of Yields in 1 second: "
   Return
End Sub
Call RunPerfTest()