引数とは関数呼び出しやスクリプト実行時にコマンドライン引数として渡す値(関数やスクリプトが受け取ることを想定している値)の事です。
引数には厳密には仮引数と実引数があります。
仮引数は、例えばC/C++のmain関数にある[argc]や[argv]、Javaのmain関数にある[args]などのように関数それ自体に往々にして型とセットで記述され、渡す際には、必ずしもその名称で渡す必要のない引数などを指します。
実引数は、例えば標準出力関数(シェルのechoやprintf、Cのprintf、Javaのprintlnなど)に渡す引数もそうですが、それ自体に値として引き渡される引数などを指します。
Perlにおける引数もスクリプトの実行時、組み込み関数やメソッド/サブルーチンコール時に渡す値を引数と呼びます。
尚、伝統的なPerlでは関数をルーチン/サブルーチンと呼び、オブジェクト指向Perl(OO Perl)ではメソッドと呼びます。
sub abc (arg1,arg2){
~ ;
}
但し、Perlでは厳密な型も宣言する必要がないので他に見られるような型もなく、その架空の仮引数名を参照しても何も取得できませんし、前述のように引数の数が不一致でも無視され意味をなしません。
但し、無視されることを利用して仮引数を記述することもできますし、宣言は必須ではありませんが、指定できないわけではなく、引数の種類を特定したい場合には、仮引数はともかく、変数に付加する$、@、%、*の接頭辞等々をプロトタイプとなるサブルーチンの丸カッコ内に指定することで引数としてとる種類を制限することは可能です。
よってPerlではサブルーチン自体の仮引数は指定する必要がなく、一般に引数部は書きません。
sub abc ( ) {
~ ;
}
その上でPerlのサブルーチンは、サブルーチン名に( )を伴って記述することができます。
sub abc {
~ ;
}
またサブルーチン名の後の( )を省略することもできます。
これは、Perlが、型を厳密に区別しない仕様であることに起因していて、(変数に格納された値の)型はPerlが自動的に認識してくれます。
このため、Perlには、$、@、%などのプレフィックス・プレフィクス(prefix/前置詞・接頭辞)のある$abc、@abc、%abcのような各種変数がありますが、いずれも変数自体に代入する値の型を指定する必要がないのでC言語などのようにキャストしたりすることもなく、更に名称に同じabcを使っていても全く別物として扱う仕様になっています。
&abc ( arg1 , arg2 );
とは言え、当然、サブルーチンを呼ぶ際に引数を渡すことはできるわけで、バージョンやケースによっては&を省略できる場合もありますが、このように関数名の前に&を付けてコールします。
my $foo="xyz";
@array=split /=/, $bar;
print $hoge, "\n";
ちなみにmy()/our()/local()やsplit()、print()など組み込み関数やモジュールの関数、クラスのメソッドのように予め宣言されていれば( )も省略することもできますが、省略されているだけでそれらに与えられる条件や式も引数です。
Perlでは前述のようにサブルーチンの仮引数は通常書くことはなく、仮に書いて参照しても使えないわけですが、その代わりにサブルーチンが引数を受け取る方法としてPerlに組み込まれた特殊な変数を使う方法が用意されています。
@_
引数を伴うサブルーチン呼び出しの場合は、呼び出される側のサブルーチンは特殊な配列変数@_を介して引数の内容を知ることができるようになっています。
# 添え字の最大値
$#_;
# 要素数
$#_+1;
引数の数は、「$#配列名」が最後の要素の添え字を表すことから配列要素が0から始まるPerlの場合、「$#配列名+1」とすれば要素数を得ることができ、@_の場合、要素数は、$#_+1です。
「@_」は配列ですから、Perlの場合、ひとつひとつの要素は0から始まる添え字付きで$_[0],$_[1],$_[2]...$_[n]とすれば参照可能です。
@ARGV
一方、スクリプトが受け取る引数は、@ARGVという特殊変数に自動的に格納されることになっています。
# 添え字の最大値
$#ARGV;
# 要素数
$#ARGV+1;
引数の数は、「$#配列名」が最後の要素の添え字を表すことから配列要素が0から始まるPerlの場合、「$#配列名+1」とすれば要素数を得ることができ、@ARGVの場合、要素数は、$#ARGV+1です。
「@ARGV」も配列ですから、ひとつひとつの要素は0から始まる添え字付きで$ARGV[0],$ARGV[1],$ARGV[2]...$ARGV[n]とすれば参照可能です。
$under_score_cnt = @_;
$argv_cnt = @ARGV;
$foo_cnt = @foo;
尚、 @_ や @ARGV を含め、Perlのこうした@で始まる配列は、スカラー変数に代入することで要素数を得ることができるようになっています。
# 引数が1つの場合
$element=shift @_;
$element=shift @ARGV;
# 引数が複数ある場合
@elements=shift @_;
@elements=shift @ARGV;
@_と@ARGVは共に格納順が保持されるので0から始まる数値をキーとした配列ということもできますが、Perlには、こうした配列を処理する関数がいくつかあります。
その中でも引数は複数ある場合、その順が重要となることもあるので引数を処理する際には配列の先頭要素を取り出すshift関数が、しばしば利用されます。
# 引数が1つの場合
$element=shift;
# 引数が複数ある場合
@elements=shift;
但し、@_と@ARGVは明記せずともPerlが該当する値を自動的に格納してくれる特殊な変数なので、@_や@ARGVを省略することができます。
sub foo {
shift;
print "$_\n";
}
更に処理する引数が1つ、またはループ中で都度異なる変数を伴ってサブルーチンが呼ばれる場合などにおいては、前述の特殊な変数[$_]と併用すると代入をも省略することができます。
sub foo {
print "$_\n"; # NG
print "$_[0]\n"; # OK
}
ここまで来ると[shift;]まで省略できてしまいそうな気にもなろうかというところではありますが、そうはいかず、この場合shift関数なくして[$_]で受け取ることはできません。
なぜなら、そもそも$_はサブルーチンの引数を受け取る変数として用意されたものではなく、その為の変数として別途@_があり、引数はこの@_に格納されるのであり、このサンプルにおいては、その@_を省略できる上でのshift関数なので、その[shift;]をも使わないのであれば省略されている@_という特殊な配列の1要素として先頭なら$_[0]のように添え字を付けて参照する必要があるからです。
尚、前述の通り、$abc、@abc、%abcが同じabcであっても別物であるように$_と$_[0]も別物で前者は自動的に直前の結果を1つ取得するPerlの予約変数そのもの、後者はサブルーチンの引数を自動的に取得するPerlの特殊な配列変数@_の要素位置(この場合先頭)を表す添え字付き要素であり、配列@abcなら$abc[0]です。
つまり、$abcと@abcは異なりますが、一次元配列の要素はスカラー値として参照するので@abcの場合、スカラー変数を表す$に配列名abcと要素位置を[ ]で括った添え字として付加し、$abc[要素位置n]のように表記されることになりますが、$abc[n]と添え字のない$abcは、やはり異なる変数であるということです。
例えば、サブルーチンtest.plがあるものとします(下記サンプルでは同名にしてますが、別にJavaのclassファイルのようにファイル名とメソッド/サブルーチン名が同じである必要はありません)。
まず、スクリプト内から引数付きで呼ぶケース、次にコマンドライン引数を伴ってスクリプトを実行するケースを書きます、その違いを見てみましょう。
#!/usr/bin/perl
&test(abc,def);
sub test {
if ($#_) {
print " @_ \n";
}
}
まず、スクリプト内で引数を伴ってサブルーチンが呼び出される場合には、[ @_ ]を参照することでサブルーチンは引数を知ることができます。
この場合、引数を渡してコールしているのでif文の条件は真となり、print文で「@_」の中身が出力されます。
$ ./test.pl
abc def
配列の区切りは、既定ではスペースですから、前述のprint文ではスペース区切りで出力されています。
#!/usr/bin/perl
&test(abc,def);
exit;
sub test {
if ($#_) {
for (@_) {
print " $_ \n";
}
}
}
例えばこのように$_を利用すれば、結果は1つずつ改行されて出力されます。
もちろん、ループ変数を使って@_の要素$_[n]を順次参照することもできます。
それとは別にここで利用している特殊な変数[$_]はソースコードとして明記しなくとも自動的に直前の結果を1つだけ受け取る変数であり、逆に言えば、明記されない場合、[$_]を伴う式の一部が省略されているものとみなされます。
この例では配列を処理していますが、[$_]については配列の1要素としてではなく、直前の式の結果(foreachで取り出された値)を1つ格納するだけなので添え字も不要です。
よってサンプルでも[$_]はループされた配列の各要素に当たります。
ただ、このサンプルでは[$_]は「式の一部」というより、そういう意味では単なる「(特殊な)変数」に見えます。
@array=(perl, programming, argument);
foreach(@array) {
s/perl/Perl/ ;
s/programming/Programming/ ;
s/^argument$/Argument/ ;
}
print "@array\n";
他方、例えば連続置換を伴うケースであれば「式の一部」として認識しやすいでしょう。
Perlでは、スカラー変数に格納された値を置換する場合、[$scalar=~s///;]のようにイコールチルダ演算子を使いますが、スカラー変数に当たる変数が[$_]の場合、省略することができます。
つまり、この各行における置換式は、[$_=~s///;]が[s///;]のように省略されています(当然明記しても同じ結果になります)。
#!/usr/bin/perl
&test;
exit;
sub test {
if ($#ARGV) {
for (@ARGV) {
print " $_ \n";
}
}
}
スクリプトがコマンドライン引数を伴って呼ばれる場合には、[ @ARGV ]を参照することでサブルーチンは引数を知ることができます。
前述のようにprint文にある[$_]は直前の結果を1つだけ受け取ってくれるPerlの特殊変数です。
もちろん、ループ変数を使って@ARGVの要素$ARGV[n]を順次参照することもできます。
$ ./test.pl abc def ghi jkl mno
abc
def
ghi
jkl
mno
このように./test.plにいくつかの引数を渡して実行すると取得できていることがわかります。
[ @ARGV ]と言えばC言語の int argc 、 char* argv[ ] が浮かびます。
my $at_cnt = @_
my $argv_cnt = @ARGV
PerlにはC言語の引数の数を保持する[ argc ]はありませんが、スカラー変数に配列を代入すると要素数を取得することができます。
また前述のように[ $# ]を付加して[ @_ ]は[ $#_ ]、[ @ARGV ]は[ $#ARGV ]とすると0から始まる添え字の最大値を取得できるので、それぞれ[ $#_+1 ]、[ $#ARGV+1 ]とすれば要素数を知ることができます。
#!/usr/bin/perl
$string = "a:b:c:d:e"
if ( $string =~ / (.*):(.*):(.*):(.*):(.*) / ) {
print "$0\n";
print "$1\n";
print "$2\n";
print "$3\n";
print "$4\n";
print "$5\n";
}
Cの[ char* argv[ ] ]については、ほぼ同じですが、Perlの@ARGVの要素$ARGV[0]には1つめのコマンドライン引数が入ることになっていますが、C言語の場合、要素argv[0]には、プログラム名が格納され、引数が要素argv[1]以降に入っている点で異なります。
プログラム名が格納されるという意味でC言語のargv[ ]に似ているものにPerlでは、やはり特殊変数である$0があります。
また、Perlの特殊変数には、$1,$2...$nがあり、$1,$2...$9には正規表現のパターンマッチングにおいて直前の式の中で丸かっこ( )で括られたパターンを左から数えた順と一致したものが順次格納されます。
例えば、仮にスカラー変数$stringに[ : ]区切りの文字列の中であるパターンに当てはまるものを出力したい場合、ファイル名をtest2.plとして(実行権限を許可して)実行すれば
$ ./test2.pl
./test2.pl
a
b
c
d
e
# test.pl、test2.plには実行権限があるものとします。
# 例:$ chmod u+x test.pl
$0には(この場合[./]というパス付の)実行ファイル名である[ ./test2.pl ]が、$1~$5にはマッチした文字が入っていることがわかります。
このマッチングは例を示す以外のことは何も考慮していないので$stringに[a:b:c:d:e:f:g]など5個以上あるとPerlが5個に収まるようにその分(a:b:c)を$1に詰めて格納してくれたりします。
尚、特殊な数字付きスカラー変数は$9までしか利用できませんが、shiftして変数の値を移動させることで変数としてではなく、値としては上限なく利用することはできます。
ちなみにPerl5ではコロン2つ[::]はパッケージ(モジュール/クラス他)の関数/メソッドや変数を表す為に[パッケージ::メソッド]のように利用する特別な表記であり、Perlバージョンによってはprint文などでも期待した結果とならない場合もあるので単なる文字列であってもコロンを利用するにあたっては注意が必要です。