で、別のスタックオーバーフローの質問 レオンTimmermansがアサート:
プロトタイプを使用しないことをお勧めします。それらには用途がありますが、ほとんどの場合ではなく、間違いなくこの場合ではありません。
なぜこれが本当なのか(またはそうでないのか)?私はほとんど常に自分のPerl関数のプロトタイプを提供します。他の誰かがそれらの使用について何か悪いことを言うのを見たことがありません。
で、別のスタックオーバーフローの質問 レオンTimmermansがアサート:
プロトタイプを使用しないことをお勧めします。それらには用途がありますが、ほとんどの場合ではなく、間違いなくこの場合ではありません。
なぜこれが本当なのか(またはそうでないのか)?私はほとんど常に自分のPerl関数のプロトタイプを提供します。他の誰かがそれらの使用について何か悪いことを言うのを見たことがありません。
回答:
プロトタイプは、正しく使用すれば問題ありません。難点は、Perlのプロトタイプが、人々が期待するように機能しないことです。他のプログラミング言語のバックグラウンドを持つ人々は、プロトタイプが関数呼び出しが正しいことを確認するためのメカニズムを提供することを期待する傾向があります。つまり、引数の数とタイプが正しいことです。Perlのプロトタイプはこのタスクにはあまり適していません。悪いのは誤用です。Perlのプロトタイプには、単一の非常に異なる目的があります。
プロトタイプを使用すると、組み込み関数のように動作する関数を定義できます。
たとえば、次のような関数を定義できます。
sub mypush(\@@) { ... }
そしてそれを
mypush @array, 1, 2, 3;
\
配列への参照を取得するためにを記述する必要はありません。
一言で言えば、プロトタイプを使用すると、独自の構文糖を作成できます。たとえば、Mooseフレームワークはそれらを使用して、より一般的なOO構文をエミュレートします。
これは非常に便利ですが、プロトタイプは非常に限られています。
参照してくださいプロトタイプを、すべての血みどろの詳細についてはperlsubに。
問題は、Perlの関数プロトタイプが、人々が思っていることを実行しないことです。その目的は、Perlの組み込み関数のように解析される関数を作成できるようにすることです。
まず、メソッド呼び出しはプロトタイプを完全に無視します。オブジェクト指向プログラミングをしている場合、メソッドがどのプロトタイプを持っているかは問題ではありません。(したがって、プロトタイプは必要ありません。)
第二に、プロトタイプは厳密には強制されません。でサブルーチンを呼び出すと&function(...)
、プロトタイプは無視されます。したがって、実際には型の安全性は提供されません。
第三に、彼らは距離で不気味な行動です。(特に$
プロトタイプ。これにより、対応するパラメーターがデフォルトのリストコンテキストではなくスカラーコンテキストで評価されます。)
特に、配列からパラメーターを渡すことが難しくなります。例えば:
my @array = qw(a b c);
foo(@array);
foo(@array[0..1]);
foo($array[0], $array[1], $array[2]);
sub foo ($;$$) { print "@_\n" }
foo(@array);
foo(@array[0..1]);
foo($array[0], $array[1], $array[2]);
プリント:
a b c
a b
a b c
3
b
a b c
に関する3つの警告main::foo() called too early to check prototype
(警告が有効になっている場合)とともに。問題は、スカラーコンテキストで評価された配列(または配列スライス)が配列の長さを返すことです。
組み込みのように機能する関数を作成する必要がある場合は、プロトタイプを使用します。それ以外の場合は、プロトタイプを使用しないでください。
注:Perl 6は完全に改良された非常に便利なプロトタイプになります。この回答はPerl 5にのみ適用されます。
foo()
prints 2の呼び出しは、2つの要素のスライスの最後の要素であるためです。に変更するmy @array = qw(foo bar baz)
と、違いがわかります。(余談ですが、これがスローアウェイ型の実証的なコードで配列またはリストを0または1ベースの数値シーケンスに初期化しない理由です。コンテキスト内のインデックス、カウント、および要素間の混乱により、何度も悩まされてきました。愚かだが真実。)
a b c
はあなたのポイントをより明確にするために使用する回答を編集しました。
上記の2枚のポスターに同意します。一般に、使用$
は避けるべきです。ブロック引数を(使用する場合のプロトタイプのみ有用である&
)、グロブ(*
)、または基準プロトタイプ(\@
、\$
、\%
、\*
)
($)
プロトタイプは名前付きの単項演算子を作成します。次に、組み込みをオーバーライドする場合(インポートまたはCORE :: GLOBAL ::を使用して)、組み込みのプロトタイプに固執する$
必要があります。でも)リストコンテキストでは、組み込みの場合はスカラーコンテキストが提供されます。
一部の人々は、Perlサブルーチンのプロトタイプを見て、それが意味のないことを意味すると考えています。
sub some_sub ($$) { ... }
Perlにとって、これはパーサーが2つの引数を期待することを意味します。これは、ビルトインのように動作するサブルーチンを作成するためのPerlの方法であり、すべてが後続のコードから何を期待するかを認識しています。あなたはperlsubでプロトタイプについて読むことができます
ドキュメントを読まなければ、プロトタイプはランタイムの引数チェックまたは他の言語で見たものと同様のものを参照していると思われます。ほとんどの人がPerlについて推測するように、彼らは間違っていることが判明しました。
ただし、Perl v5.20以降、Perlには、私がこれを書いている時点で実験的な機能があり、ユーザーが何を期待し、何を期待するかのようなものを提供します。Perlのサブルーチンシグネチャは、実行時の引数のカウント、変数の割り当て、およびデフォルト設定を行います。
use v5.20;
use feature qw(signatures);
no warnings qw(experimental::signatures);
animals( 'Buster', 'Nikki', 'Godzilla' );
sub animals ($cat, $dog, $lizard = 'Default reptile') {
say "The cat is $cat";
say "The dog is $dog";
say "The lizard is $lizard";
}
これは、プロトタイプを検討している場合におそらく必要な機能です。