コンピュータプログラミングでは、パラメータ、または 仮引数は、関数呼び出しの引数を表す変数です。[ 1 ] [ 2 ] [ 3 ] [ 4 ]関数のシグネチャは、そのパラメータを定義します。呼び出しの実行には、呼び出しの各引数式を評価し、その結果を対応するパラメータに関連付けることが含まれます。
例えば、Python関数を考えてみましょう。
def add ( x : int , y : int ) -> int : return x + y変数xと はyパラメータであり、それぞれ型は ですint。 を呼び出す場合add(2, 3)、式2と は3引数です。 を呼び出す場合add(a + 1, b + 2)、引数はa + 1とですb+2。
パラメータの受け渡しはプログラミング言語によって定義されます。評価戦略は、パラメータの宣言方法と関数への引数の受け渡し方法に関するセマンティクスを定義します。一般的に、値渡しの場合、パラメータは引数の値で初期化された新しいローカル変数のように動作します。引数が変数の場合、パラメータはコピーであるため、関数は引数の状態を変更できません。参照渡しの場合、引数は変数である必要があり、パラメータは引数のエイリアスになります。
以下のCソースコードは、という名前の関数を定義し、salesTaxという名前のパラメータを 1 つprice持ちます。関数とパラメータの両方の型は ですdouble。 を呼び出すとsalesTax(10.00)、引数はdouble 型の10.00値 10として関数に渡され、パラメータ変数 に代入され、関数は 0.5 を返します。price
double salesTax ( double price ) { return 0.05 * price ; }パラメータと引数という用語は、プログラミング言語によって意味が異なる場合があります。これらの用語は互換的に使用されることもあり、文脈によって意味が区別されます。パラメータ(仮パラメータと呼ばれることもあります)という用語は、関数宣言にある変数を指すことが多く、引数(実パラメータと呼ばれることもあります)は、関数呼び出し文で実際に渡される入力を指します。たとえば、関数をとして定義した場合def f(x): ...、はパラメータであり、でx呼び出された場合、は引数です。パラメータは(非束縛)変数ですが、引数はリテラル、変数、またはリテラルと変数を含むより複雑な式になります。値渡しの場合、関数に渡されるのは引数の値です(たとえば、およびは同等の呼び出しです)。一方、参照渡しでは、引数として変数を使用する場合、渡されるのはその変数への参照です。ただし、関数呼び出しの構文は同じままです。[ 5 ]参照渡しまたは値渡しの仕様は、関数宣言および/または定義で行われます。a = ...; f(a)af(2)a = 2; f(a)
パラメーターはプロシージャ定義に現れ、引数はプロシージャ呼び出しに現れます。関数定義ではf(x) = x * x変数xはパラメーターであり、関数呼び出しではf(2)値2が関数の引数です。大まかに言えば、パラメーターは型であり、引数はインスタンスです。
パラメータとは、プロシージャの定義に含まれる、プロシージャ固有のプロパティです。例えば、多くのプログラミング言語では、与えられた2つの整数を足し合わせて合計を計算するプロシージャには、それぞれの整数に対応する2つのパラメータが必要です。一般に、プロシージャは任意の数のパラメータを持つことも、パラメータを全く持たずに定義することもできます。プロシージャにパラメータがある場合、そのパラメータを指定する定義の部分をパラメータリストと呼びます。
対照的に、引数はプロシージャが呼び出されたときにプロシージャに渡される式[ 6 ]であり、通常はパラメータの1つに一致する1つの式です。プロシージャの定義の不変の部分を形成するパラメータとは異なり、引数は呼び出しごとに変化する可能性があります。プロシージャが呼び出されるたびに、引数を指定するプロシージャ呼び出しの部分は引数リストと呼ばれます。
パラメータは引数とも呼ばれますが、引数は、実行時に関数が呼び出されたときにパラメータ変数に割り当てられる実際の値または参照を指す場合もあります。関数を呼び出すコードについて説明する場合、関数に渡される値または参照は引数であり、これらの値または参照が指定されるコード内の場所はパラメータリストです。関数定義内のコードについて説明する場合、関数のパラメータリスト内の変数はパラメータであり、実行時のパラメータの値は引数です。
次のC関数を考えてみましょう。sumこの関数は 2 つのパラメータ と を持ちますa。bパラメータに渡された値を加算し、その結果を関数の呼び出し元に返します。
int sum ( int a , int b ) { return a + b ; }以下は、 を呼び出す例ですsum。変数xと はy初期化され、sum引数として に渡されます。実行時には、これらの変数に割り当てられた値が に渡されますsum。 ではsum、パラメータaとbが評価され、それぞれ引数40とが生成されます2。引数の値が加算され、結果が呼び出し元に返され、変数 に代入されますresult。
int x = 40 ; int y = 2 ; int result = sum ( x , y );パラメーターと引数の違いにより、プロシージャに不適切な引数を渡す可能性があります。引数が多すぎたり少なすぎたり、引数の型が間違っていたり、引数の順序が間違っていたりする場合があります。これらのいずれの場合も、パラメーターと引数のリストに不一致が生じ、プロシージャは意図しない結果を返したり、実行時エラーを発生させたりすることがよくあります。
Eiffelソフトウェア開発手法および言語では、引数とパラメータという用語は慣例によって異なる用途で使用されます。引数という用語はルーチンの入力を参照する場合にのみ使用され、[ 7 ]パラメータという用語はジェネリッククラスの型パラメータ化にのみ使用されます。[ 8 ]
次のルーチン定義を考えてみましょう。
sum ( a : INTEGER ; b : INTEGER ): INTEGER do Result := a + b endこのルーチンsumは 2 つの引数aとを受け取りますb。これらはルーチンの仮引数と呼ばれます。 の呼び出しでは、以下に示すように、と を用いた実際の引数sumを指定します。xy
結果: INTEGER x : INTEGER = 40 y : INTEGER = 2 …結果:= sum ( x , y )パラメータは、形式パラメータと実パラメータに分類されます。形式ジェネリックパラメータは、ジェネリッククラスの定義に使用されます。以下の例では、クラスはジェネリッククラスとして宣言されており、対象となるデータとデータのハッシュキーを表すHASH_TABLE 2つの形式ジェネリックパラメータを持っています。GK
class HASH_TABLE [ G , K -> HASHABLE ] …クラスが のクライアントになるとHASH_TABLE、形式的なジェネリック パラメータは、ジェネリック派生の実際のジェネリック パラメータに置き換えられます。次の属性宣言では、は文字列ベースの辞書として使用されます。そのため、データとキーの両方の形式的なジェネリック パラメータは、型の実際のジェネリック パラメータに置き換えられます。my_dictionarySTRING
my_dictionary : HASH_TABLE [ STRING , STRING ]厳密な型付けを持つプログラミング言語では、各パラメータの型はプロシージャ宣言で指定する必要があります。型推論を使用する言語は、関数の本体と使用箇所から型を自動的に検出しようとします。動的型付けを持つプログラミング言語は、実行時まで型解決を延期します。弱い型付けを持つ言語は、型解決をほとんど、あるいは全く行わず、代わりにプログラマの正確性に依存します。
void一部の言語では、関数にパラメータがないことを示すために特別なキーワード(例:)を使用します。形式型理論voidでは、このような関数は空のパラメータリスト(型はではなく、ユニット)を受け取ります。
引数をパラメータに割り当てる仕組みは、引数渡しと呼ばれ、そのパラメータに使用される評価戦略(通常は値渡し)に依存します。この評価戦略は、キーワードを使用して指定できます。
Ada、C++、Clojure、Common Lisp、[ 9 ] Fortran 90、[ 10 ] Python、Ruby、Tcl、Windows PowerShellなどの一部のプログラミング言語では、関数の宣言でデフォルト引数を明示的または暗黙的に指定できます。これにより、呼び出し元は関数を呼び出すときにその引数を省略できます。デフォルト引数が明示的に指定されている場合、呼び出し元によって値が指定されていない場合はその値が使用されます。デフォルト引数が暗黙的である場合(Optionalなどのキーワードを使用することによって)、呼び出し元によって値が指定されていない場合は、言語は既知の値(null、Empty、ゼロ、空の文字列など)を提供します。
PowerShell の例:
function doc ( $g = 1 . 21 ) { "$g ギガワット? $g ギガワット? なんてこった!" }PS >ドキュメント1.21ギガワット? 1.21ギガワット? なんてこった!PS > doc 88 88ギガワット? 88ギガワット? なんてこった!デフォルト引数は、可変長引数リストの特殊なケースとみなすことができる。
一部のプログラミング言語では、可変個の引数を受け取る関数を定義できます。そのような言語では、関数は引数のリストを順に処理する必要があります。
PowerShell の例:
function marty { $args | foreach { "back to the year $_" } }PS >マーティ1985 1985年に戻るPS >マーティ2015 1985 1955 2015年に戻る 1985年に戻る1955年に戻るAdaやWindows PowerShellなどの一部のプログラミング言語では、関数に名前付きパラメータを設定できます。これにより、呼び出し元のコードの自己説明性が向上します。また、呼び出し元にも柔軟性がもたらされ、引数の順序を変更したり、必要に応じて引数を省略したりすることが可能になります。
PowerShell の例:
function jennifer ( $adjectiveYoung , $adjectiveOld ) { "若いジェニファー: 私は$adjectiveYoungです! "年老いたジェニファー: 私は$adjectiveOldです!}PS >ジェニファー「フレッシュ」「経験豊富」若いジェニファー:私はフレッシュよ!年老いたジェニファー:私は経験豊富よ!PS > jennifer -形容詞Old 'experienced' -形容詞Young 'fresh'若いジェニファー: 私はフレッシュよ!年老いたジェニファー: 私は経験豊富よ!ラムダ計算では、各関数はパラメータをちょうど 1 つだけ持ちます。複数のパラメータを持つ関数と考えられているものは、通常、ラムダ計算では最初の引数を受け取り、残りの引数を受け取る関数を返す関数として表現されます。これはカリー化と呼ばれる変換です。MLやHaskellなどの一部のプログラミング言語は、この方式を採用しています。これらの言語では、すべての関数はパラメータをちょうど 1 つだけ持ち、複数のパラメータを持つ関数の定義のように見えるものは、実際には関数を返す関数の定義の構文糖衣です。これらの言語とラムダ計算では、関数の適用は左結合であるため、複数の引数への関数の適用のように見えるものは、最初の引数に適用された関数、次に結果として得られた関数が 2 番目の引数に適用される、といったように正しく評価されます。
出力パラメータ(out パラメータまたはreturn パラメータとも呼ばれる)は、入力によく使われるパラメータではなく、出力に使用されるパラメータです。参照渡しパラメータ、または値が参照である値渡しパラメータを出力パラメータとして使用することは、C や C++ などの一部の言語の慣用表現ですが、他の言語では出力パラメータが組み込まれています。出力パラメータが組み込まれている言語には、Ada [ 11 ] ( Ada サブプログラムを参照)、Fortran ( Fortran 90以降、 Fortran "intent"を参照)、PL/SQL ( PL/SQL 関数を参照)[ 12 ]やTransact-SQLなどのSQLのさまざまな手続き型拡張機能、C# [ 13 ]および.NET Framework [ 14 ] Swift [ 15 ]、スクリプト言語TScript(TScript 関数宣言を参照)などがあります。
以下は、C++における「出力パラメータ」の例です。
// 出力パラメータを持つ関数の定義void sum ( int x , int y , int & out ) { out = x + y ; }// 使用例: int foo = 1 ; int bar = 2 ; int baz ; sum ( foo , bar , baz );この関数は何も返しませんが、 の値はとして参照が渡されたx + y変数に代入されます。out
より正確には、パラメータまたはパラメータモードは3種類に分類できる。入力パラメータs、出力パラメータ、および入力/出力パラメータ。これらは通常in、、、outまたはin outでinout。入力引数(入力パラメータへの引数)は、初期化された変数やリテラルなどの値である必要があり、再定義または代入してはなりません。出力引数は代入可能な変数である必要がありますが、初期化されている必要はなく、既存の値にはアクセスできず、値を代入する必要があります。入力/出力引数は、初期化された代入可能な変数である必要があり、オプションで値を代入できます。正確な要件と適用方法は言語によって異なります。たとえば、Ada 83出力パラメータは代入のみ可能で、代入後でも読み取りはできません(これは、補助アキュムレータ変数の必要性をなくすためにAda 95値がそれぞれ rvalue(値を持つ)、lvalue(代入可能)、または rvalue/lvalue(値を持ち、かつ代入可能)であるという概念に類似していますが、これらの用語は C および C++ では特別な意味を持ちます。
場合によっては、入力と入出力のみが区別され、出力は入出力の特定の用途とみなされます。また、入力と出力のみがサポートされ、入出力はサポートされない場合もあります。デフォルトモードは言語によって異なります。Fortran 90では入出力がデフォルトですが、C#とSQL拡張機能では入力がデフォルトであり、TScriptでは各パラメーターが入力または出力として明示的に指定されます。
構文的には、パラメータモードは一般的に、C# のように関数宣言内のキーワードで示されます。慣例として、出力パラメータは明確に区別するためにパラメータリストの最後に配置されることが多いですが、必ずしもそうとは限りません。TScript では異なるアプローチが採用されており、関数宣言では入力パラメータがリストされ、次に出力パラメータがコロン (:) で区切られてリストされます。また、このテキストフラグメントのサイズを計算する関数のように、関数自体には戻り値の型がありません。voidFn(outintx)
TextExtent ( WString text 、Font font : Integer width 、Integer height )パラメータ モードは、プログラマの意図を示し、コンパイラがエラーを検出して最適化を適用できるようにする、表示的意味論の一形態です。これは、操作的意味論(パラメータの受け渡しが実際にどのように行われるか) を必ずしも意味するものではありません。特に、入力パラメータは値渡しで、出力および入出力パラメータは参照渡しで実装できますが、組み込みのサポートがない言語では、これがこれらのモードを実装する簡単な方法です。しかし、常にこのように実装されるとは限りません。この区別については、Ada '83 Rationale で詳しく説明されており、パラメータ モードは、実際に実装されるパラメータ受け渡しメカニズム (参照渡しまたはコピー渡し) から抽象化されていることが強調されています。[ 11 ]例えば、C# では入力パラメータ (デフォルト、キーワードなし) は値渡しされ、出力および入出力パラメータ (outおよびref) は参照渡しされますが、PL/SQL では入力パラメータ ( IN) は参照渡しされ、出力および入出力パラメータ (OUTおよびIN OUT) はデフォルトでは値渡しされ、結果がコピーバックされますが、NOCOPYコンパイラヒントを使用することで参照渡しにすることができます。[ 16 ]
出力パラメータと構文的に類似した構造として、戻り値を関数と同じ名前の変数に代入する方法があります。これは、Pascal、Fortran 66、Fortran 77に見られ、次の Pascal の例を参照してください。
function f ( x , y : integer ) : integer ; begin f := x + y ; end ;これは意味的に異なり、呼び出されたときに、関数は単に評価されるだけで、出力を格納するための変数が呼び出し元のスコープから渡されることはありません。
出力パラメータの主な用途は、関数から複数の値を返すことですが、入出力パラメータの用途は、パラメータ渡しを使用して状態を変更することです(グローバル変数のように共有環境を使用するのではなく)。複数の値を返す重要な用途は、値とエラー状態の両方を返すという半述語問題を解決することです( 「半述語問題:多値戻り値」を参照)。
例えば、C言語の関数から2つの変数を返すには、次のように記述します。
int幅; int高さ;f ( x , & width , & height );ここでx、は入力パラメータであり、widthおよびheightは出力パラメータです。およびのアンパサンドは&width、および&heightのメモリ アドレスを表します。widthheight
C 言語や関連言語でよく使われるユースケースは例外処理で、関数が戻り値を出力変数に格納し、関数が成功したか失敗したかに対応するブール値を返します。典型的な例は、TryParse.NET、特に C# のメソッドで、文字列を整数に解析し、true成功した場合は を、false失敗した場合は を返します。そのシグネチャは次のとおりです。 [ 17 ]
public static bool TryParse ( string s , out int result )そして、以下のように使用することができます。
Systemを使用します。int result ; if ( ! Int32.TryParse ( s , result ) ) { // 例外処理}複数の可能な型のいずれかの値を返す場合にも同様の考慮事項が適用されます。この場合、戻り値で型を指定し、その値を複数の出力変数のいずれかに格納することができます。
出力パラメータは、現代のプログラミングでは、扱いにくく、混乱を招きやすく、低レベルすぎるため、推奨されないことが多い。一般的な戻り値の方が、はるかに理解しやすく、扱いやすい。[ 18 ]特に、出力パラメータは副作用(出力パラメータを変更する)のある関数を含み、意味的には参照に似ているが、参照は純粋な関数や値よりも混乱を招きやすく、出力パラメータと入出力パラメータの区別は微妙になることがある。さらに、一般的なプログラミングスタイルでは、ほとんどのパラメータは単なる入力パラメータであるため、出力パラメータと入出力パラメータは珍しいものであり、誤解を招きやすい。
出力と入出力パラメータは関数合成を妨げます。なぜなら、出力は式の値ではなく変数に格納されるからです。したがって、最初に変数を宣言し、関数チェーンの各ステップを個別のステートメントにする必要があります。たとえば、C++ では次の関数合成が考えられます。
MyObject obj = g ( y , f ( x ));出力と入出力パラメータで記述すると、代わりに次のようになります(F出力パラメータの場合は、G入出力パラメータの場合は)。
MyObject obj ; f ( x , & obj ); g ( y , & obj );出力または入出力パラメータが1つだけで戻り値のない関数の特殊なケースでは、出力または入出力パラメータ(C/C++ではそのアドレス)が関数によって返される場合、関数合成が可能となり、上記は次のようになります。
MyObject obj ; g ( y , f ( x , & obj ));出力パラメータの使用例には、さまざまな代替案が存在する。
関数から複数の値を返す場合、タプルを返すという方法もあります。GoやPythonのように、自動的なシーケンス展開と並列代入が利用できる場合、構文的にはより明確になります。例えば、次のようになります。
def f () -> tuple [ int , int ]: return 1 , 2 a , b = f ()複数の型のいずれかの値を返すには、タグ付き共用体を使用できます。最も一般的なケースは、null許容型(オプション型)で、戻り値は失敗を示すためにnullになります。例外処理では、null許容型を返すか、例外を発生させることができます。たとえば、Pythonでは、次のいずれかになります。
結果: str = parse ( s )結果がNoneの場合: # 例外処理あるいは、より慣用的な言い方をすれば:
try : result : str = parse ( s ) except ParseError : # 例外処理出力変数を使用する際にローカル変数を必要とせず、戻り値をコピーするというマイクロ最適化は、十分に高度なコンパイラであれば、従来の関数や戻り値にも適用できる。
C言語や関連言語における出力パラメータの一般的な代替手段は、すべての戻り値を含む単一のデータ構造を返すことである。[ 13 ]例えば、幅と高さをカプセル化した構造体がある場合、次のように記述できる。
幅高さwh = f ( x );オブジェクト指向言語では、入出力パラメータを使用する代わりに、共有による呼び出し、つまりオブジェクトへの参照を渡してオブジェクトを変更する(ただし、変数が参照するオブジェクトは変更しない)ことがよく行われる。[ 18 ]
パラメータとは、メソッド宣言内の変数のリストを指します。引数とは、メソッドが呼び出されたときに実際に渡される値です。メソッドを呼び出すときは、使用する引数は宣言のパラメータと型と順序が一致している必要があります。