perlの$_[0](デフォルト引数)とか@_(引数リスト)について気になったので調べた

とあるperlのコードを読んでみると、下記のような書き方をしていて気になったので、調べてみました。

sub on { push @{$_[0]{events}{$_[1]}}, $_[2] and return $_[2] }

@_(引数リスト)とは?

@_(引数リスト)とは、サブルーチン(関数)やforforeachなどの制御構文を扱う時に、引数の受け皿となる配列です。

普通、引数と言えば下記のRubyコードのようにプログラマ自身が用意してあげて、関数の呼び出し時に引数に値が代入されるのが一般的です。

# Ruby
def hello(name, age) {
  puts 'hello' + name + age // hello tarou 19
end

hello('tarou', 19)

しかし、perlでは@_(引数リスト)が用意されており、その引数リストに代入すると言う形を取っています。

perlにはData::Printerと言う変数のデータ構造を見るのに便利なモジュール(他言語で言うライブラリ)があるので、早速@_の中身を見てみましょう。

use Data::Printer;
sub hello {
  p @_;
};

hello('tarou', 19);

= result
[
    [0] "tarou",
    [1] 19
]

確かに@_引数リストに引数が代入されているのが分かりますね。

$[0]とか$[1]とかの使い方

上記の説明で@_に引数が入ることが分かりましたが、引数リストの要素を1つずつ取り出したい時が絶対にあるはずです。そう言う時には、$_[0]を使うと良いです。

実際に以下のコードで試してみます。

use Data::Printer;

sub hello {
    p $_[0];
    p $_[1];
    p $_[2];
    p @_;
}

hello( 'tarou', 19 );

= result
"tarou"
19
undef
[
    [0] "tarou",
    [1] 19,
    [2] undef
]

上記では引数を2つしか与えていないので$_[2] = undefになるのは分かるのですが、$_[2]と1回定義した影響で@_(引数リスト)に3番目の引数が作られているのが興味深いっすね。

クラスやインスタンス(オブジェクト)での@_の動き

実際のところ上記の例のように関数だけを使うよりも、関数はクラスの中でメソッドとして使うことの方が多いでしょう。

package Sample {
    use Data::Printer;
    use Moo;

    sub hello {
        p @_;
    }
};

my $self = Sample->new;
$self->hello( 2, 43 );

= result
[
    [0] Sample  {
        Parents       Moo::Object
        public methods (1) : hello
        private methods (0)
        internals: {}
    },
    [1] 2,
    [2] 43
]