コンピュータ プログラミングでは、return ステートメントによって、現在のサブルーチンの実行が終了し、サブルーチンを呼び出した命令の直後のコード ポイント (戻りアドレスと呼ばれる) から再開されます。戻りアドレスは呼び出しルーチンによって保存され、現在は通常、プロセスの呼び出しスタックまたはレジスタに保存されます。多くのプログラミング言語の return ステートメントでは、関数を呼び出したコードに返す戻り値を指定できます。
概要
CおよびC++では、(は式)は関数にプログラムの実行を呼び出し元の関数に返し、 の値を報告するよう指示する文です。関数の戻り値の型がvoidの場合、 return 文を値なしで使用できます。その場合、プログラムは現在の関数から抜け出し、呼び出し元の関数に戻ります。[1] [2]同様の構文は、 Modula-2 [3]やPythonなどの他の言語でも使用されています。[4]return exp;expexp
Pascalにはreturn 文はありません。関数や手続きは、最後の文に到達すると自動的に戻ります。関数からの戻り値は、関数と同じ名前の識別子に割り当てることで関数内で提供されます。[5]ただし、Pascal の一部のバージョンでは、関数からすぐに値を返したり、パラメータなしで手続きからすぐに戻ったりできる特別な関数が提供されています。 [6]Exit(exp);
Pascalと同様に、FORTRAN II、Fortran 66、Fortran 77、およびそれ以降のバージョンのFortranでは、関数名への代入によって戻り値を指定しますが、return文も持っています。この文は戻り値を指定せず、関数の場合は関数名に割り当てられた値を返します。[5] [7] [8]
他の言語では関数識別子の代わりにユーザー定義の出力パラメータが使用される。 [9]
Oberon(Oberon-07)にはreturn文の代わりにreturn句があります。return句は手続き本体の最後の文の後に置かれます。[10]
Lisp、Perl、Rubyなどの一部の式指向プログラミング言語では、プログラマが明示的なreturn文を省略し、代わりに最後に評価された式がサブルーチンの戻り値になるように指定することができます。その他のケースでは、明示的なreturn文がない場合はNull値が返されます。Pythonでは、 return文が省略されると値が返されますが、 [4] JavaScriptでは値が返されます。
Noneundefined
Windows PowerShellでは、キャプチャされないすべての評価済み式 (変数への割り当て、voidへのキャスト、または$nullへのパイプなど) は、サブルーチンから配列内の要素として返されるか、キャプチャされていないオブジェクトが 1 つだけの場合は単一のオブジェクトとして返されます。
Perl では、サブルーチンの戻り値は、呼び出されたコンテキストによって異なります。最も基本的な区別は、呼び出しコードが 1 つの値を期待するスカラーコンテキスト、呼び出しコードが値のリストを期待するリストコンテキスト、および呼び出しコードが戻り値をまったく期待しないvoidwantarrayコンテキストです。サブルーチンは、関数を使用してコンテキストを確認できます。引数なしの return という特別な構文は、スカラー コンテキストで未定義の値を返し、リスト コンテキストで空のリストを返すために使用されます。スカラー コンテキストは、ブール値、数値、文字列、およびさまざまな参照型のコンテキストにさらに分類できます。また、コンテキスト依存のオブジェクトは、スカラー値の遅延評価を伴うコンテキスト戻りシーケンスを使用して返すことができます。
多くのオペレーティング システムでは、プロセスが終了したときにプログラムが結果 (通常の出力とは別) を返すことができます。これらの値は終了ステータスと呼ばれます。この方法で渡すことができる情報の量は非常に限られており、実際には成功または失敗のシグナルのみに制限されることがよくあります。プログラム内からこの戻りは通常、Exit (システム コール)を呼び出すことによって実現されます (メイン関数から戻る代替メカニズムが利用できる C でも一般的です)。
構文
return ステートメントにはさまざまな形式があります。最も一般的な構文は次のとおりです。
一部のアセンブリ言語、たとえばMOS Technology 6502のアセンブリ言語では、ニーモニック「RTS」(ReTurn from Subroutine) が使用されます。
複数の return ステートメント
明示的な return ステートメントを持つ言語では、同じ関数内に複数の return ステートメントが存在する可能性があります。これが良いことかどうかは議論の余地があります。
構造化プログラミングの熱心な支持者は、各関数が単一のエントリと単一の終了 (SESE) を持つようにします。したがって、サブルーチンのテキストの最後以外では、明示的な return ステートメントの使用を避けるべきだと主張されています[14] 。これは、早期に復帰するために使用すると、 GOTOステートメントで発生するのと同じ種類の問題が発生する可能性があることを考慮するためです。逆に、代替案が、より深いネストなどのより複雑なコードで、可読性が損なわれる場合は、return ステートメントを使用する価値があると主張することもできます。
2004 年の教科書で、デイビッド・ワットは「単一エントリのマルチエグジット制御フローが望ましい場合が多い」と書いている。ワットは、テネントのシーケンサーのフレームワーク概念を使用して、現代のプログラミング言語に見られる制御フロー構造を統一的に説明し、マルチエグジット制御フローのコンテキストで特定のタイプのシーケンサーが他のタイプよりも好ましい理由を説明しようとしている。ワットは、制限のない goto (ジャンプ シーケンサー) は、ジャンプの宛先がプログラムの読者にとって自明ではなく、読者がジャンプのターゲットである実際のラベルまたはアドレスを見つけて調べるまでは不明であるため、良くないと書いている。対照的に、ワットは、リターン シーケンサーの概念的な意図は、宛先を調べなくても、それ自体のコンテキストから明らかであると主張している。さらに、ワットは、エスケープ シーケンサーと呼ばれるシーケンサーのクラスは「テキストで囲まれたコマンドまたはプロシージャの実行を終了するシーケンサー」と定義され、ループからのブレーク(マルチレベル ブレークを含む) と return ステートメントの両方を含むと書いている。ワットはまた、ジャンプ シーケンサー (goto) は C 言語のような言語ではある程度制限されており、ターゲットはローカル ブロック内または外側のブロック内である必要がありますが、その制限だけでは C 言語の goto の意図を自己記述的にするには不十分であり、依然として「スパゲッティ コード」が生成されると指摘しています。ワットはまた、例外シーケンサーがエスケープ シーケンサーやジャンプ シーケンサーとどのように異なるかを調べています。詳細については、構造化プログラミングに関する記事を参照してください。[15]
エリック・S・ロバーツが引用した実証研究によると、学生プログラマーは、複数の終了点を許可しないパスカルのような言語では、いくつかの単純な問題に対する正しい解法を策定するのが困難でした。配列内の要素を線形に検索する関数を書く問題では、ヘンリー・シャピロによる1980年の研究(ロバーツが引用)によると、パスカルが提供する制御構造のみを使用した場合、正しい解を与えたのは被験者のわずか20%でしたが、ループの途中から戻りを記述することを許可された場合、この問題に対して誤ったコードを書いた被験者はいませんでした。[16]
ケント・ベックやマーティン・ファウラーを含む他の人々は、1つ以上のガード句(関数の先頭近くにある条件付きの「早期終了」戻り文)により、他の方法よりも関数が読みやすくなると主張している。[17] [18] [19] [20]
早期終了で最も一般的な問題は、クリーンアップまたは最終ステートメントが実行されないことです。たとえば、割り当てられたメモリが割り当て解除されていない、または開いているファイルが閉じられていないため、リークが発生します。これらは各戻りサイトで実行する必要がありますが、これは脆弱であり、簡単にバグが発生する可能性があります。たとえば、後の開発で、開発者が戻りステートメントを見落とし、サブルーチンの最後に実行する必要があるアクション (トレースステートメントなど) がすべてのケースで実行されない可能性があります。標準 Pascal などの戻りステートメントのない言語では、この問題はありません。C++ や Python などの一部の言語では、戻り (または例外スロー) 時にアクションを自動的に実行できるようにする概念が採用されており、これらの問題の一部が軽減されます。これらは、多くの場合、「try/finally」などとして知られています。これらの「finally」句のような機能は、サブルーチンの単一の戻りポイントへの goto によって実装できます。別の解決策としては、関数終了時に通常のスタックのアンワインド (変数の割り当て解除) を使用して、ローカル変数のデストラクタや、Python の "with" ステートメントなどの同様のメカニズムなどを使用してリソースの割り当てを解除します。
オリジナルの Pascal や C などの言語の初期の実装では、コンパイラを簡素化するために、関数によって返される型が制限されていました (たとえば、レコード型や構造体型をサポートしていないなど) 。
Javaや、それをモデルにしたJavaScriptなどの類似言語では、 try-catch 構造のfinallyブロックが常に実行されるため、return 文の後でもコードを実行することができます。したがって、 return文がtryまたはcatchブロック内のどこかに配置されている場合は、finally内のコード(追加されている場合) が実行されます。exit もその後に発生するため、非プリミティブ型 (すでに返されたオブジェクトのプロパティ) の戻り値を変更することも可能です。[21]
利回りステートメント
return ステートメントの類似品はyield ステートメントです。return はサブルーチンを終了させ、 yieldはコルーチンを一時停止させます。コルーチンは、再度呼び出されると一時停止したところから再開されます。コルーチンの実装はサブルーチンよりもはるかに複雑であるため、yield ステートメントは return ステートメントほど一般的ではありませんが、多くの言語で使用されています。
呼び出し/戻りシーケンス
ハードウェア命令セットに応じて、次のようなさまざまな呼び出し/戻りシーケンスが可能です。
- 命令はスタック上の次の
CALL命令のアドレスをプッシュし、指定されたアドレスに分岐します。命令はスタックから戻りアドレスを命令ポインタにポップし、そのアドレスから実行を再開します。(例: x86、PDP-11 ) Motorola 96000などのアーキテクチャでは、スタック領域は「スタックメモリ空間」と呼ばれる別のアドレス空間に割り当てられることがあります。 [22]メインメモリアドレス空間とは区別されます。[23] NEC μPD7720にも、独自の別のアドレス空間を持つスタックが搭載されています。[24]RETURN - 命令は、次の
CALL命令のアドレスをレジスタに格納し、指定されたアドレスに分岐します。命令シーケンスは、レジスタからの戻りアドレスを命令ポインタに格納し、そのアドレスから実行を再開します。(例: IBM System/360およびz/Architecture経由の後継、ほとんどのRISCアーキテクチャ)RETURN - この命令は、呼び出しアドレスの記憶域に次の(または現在の
CALL)命令のアドレスを配置し、指定されたアドレス+1に分岐します。命令シーケンスは、サブルーチンの最初の命令への間接ジャンプによって戻りアドレスに分岐します。(例:IBM 1130、SDS 9XX、PDP-8)RETURN
参照
注記
- ^ Bourneシェルでは、0~255の範囲の整数のみが返される可能性がある[11]
参考文献
- ^ ab "return ステートメント (C)". Microsoft Docs . 2023 年 1 月 25 日。
- ^ ab "return ステートメント (C++)"。Microsoft Docs 2021 年 8 月 3 日。
- ^ Gleaves, R. (2012). Modula-2 for Pascal Programmers. Springer. p. 71. ISBN 9781461385318。
- ^ abc Martelli, Alex (2006). Python in a Nutshell: デスクトップクイックリファレンス (第2版). O'Reilly Media. p. 73. ISBN 9781449379100。
- ^ ab スコット、マイケル L. (2006)。プログラミング言語語用論。モーガン カウフマン。p. 432。ISBN 9780126339512。
- ^ フランダース、ハーレー (2012). Scientific Pascal. シュプリンガー. p. 35. ISBN 9781461224280。
- ^ ANSI x3.9-1966. USA Standard FORTRAN (PDF) . American National Standards Institute. p. 14. 2011年5月15日時点のオリジナル(PDF)からアーカイブ。2010年5月5日閲覧。
{{cite book}}: CS1 maint: 数値名: 著者リスト (リンク) - ^ ANSI x3.9-1978。アメリカ国家規格 - プログラミング言語 FORTRAN。アメリカ国家規格協会。15.8 RETURN ステートメント。2013 年 10 月 29 日時点のオリジナルよりアーカイブ。2007年12 月 11 日閲覧。
{{cite book}}: CS1 maint: 数値名: 著者リスト (リンク) - ^ Sakkinen, Markku (1989年3月). 「関数の値を最もよく返す方法」. ACM SIGPLAN Notices . 24 (3). Association for Computing Machinery: 55–56. doi : 10.1145/66083.66087 .
- ^ Wirth, Niklaus (2016 年 5 月 3 日)。「10. プロシージャ宣言」。プログラミング言語 Oberon (PDF) (レポート)。p. 11。
- ^ 「return - 関数またはドット スクリプトからの戻り」。Single UNIX 仕様。
- ^ 「PHP: return - マニュアル」。PHPマニュアル。PHP グループ。2013年3 月 26 日閲覧。
- ^ 「Return - Javascript」。MDN Javascript リファレンス。Mozilla Developer Network。2013年3 月 27 日閲覧。
- ^ Swartz, Fred. 「C++ ノート: 関数 return ステートメント」。
- ^ Watt, David Anthony; Findlay, William (2004).プログラミング言語設計コンセプト. John Wiley & Sons. pp. 215–221. ISBN 978-0-470-85320-7。
- ^ Roberts, E. (1995 年 3 月). 「ループ終了と構造化プログラミング: 議論の再開」. ACM SIGCSE 速報. 27 (1): 268–272. doi : 10.1145/199691.199815 .
- ^ Martin Fowler、Kent Beck、John Brant、William Opdyke、Don Roberts (2012)。リファクタリング: 既存コードの設計の改善 (Google eBook)。Addison-Wesley。pp. 237、250。ISBN 9780133065268...
1 つの終了ポイントの考え方 ... メソッドからの 1 つの終了ポイントに関するルールには従いません。
- ^ Kent Beck (2007)。「7: 動作」。実装パターン。Pearson Education。セクション「ガード句」。ISBN 9780132702553。
- ^ 「複数の return ステートメント」。Javaプラクティス。
- ^ Fred Swartz. 「Return ステートメントと単一の終了ファンタジー」。2020 年 2 月 23 日時点のオリジナルよりアーカイブ。
- ^ 「finally ブロック」。Javaチュートリアル。
- ^ 「DSP96002 32ビットデジタルシグナルプロセッサユーザーズマニュアル」(PDF) . p. 27(3 - 4) . 2023年12月24日閲覧。
- ^ 「DSP96002 32ビットデジタルシグナルプロセッサユーザーズマニュアル」(PDF) . p. 50(4 - 11) . 2023年12月24日閲覧。
- ^ 「μPD77C20A、7720A、77P20 デジタル信号プロセッサ」p. 4(3a-4) 。 2023年12月25日閲覧。
