引数に複数の配列を指定

perlの場合,引数は配列@_を使用してサブプログラムへ渡ります.したがって,サブプログラムf0に3個のスカラ値を渡すプログラムは以下のようになります.

#!/usr/bin/perl -w
use strict;

sub f0{
  my @arr=@_;
  print "f0: @arr\n"; #print "f0: @_\n";でも同じ
}

f0(1,2,3);
  

3個のスカラ値を渡す上記プログラムは,3個のスカラ値からなる配列1個を渡す以下のプログラムと同じです.

#!/usr/bin/perl -w
use strict;

sub f0{
  my @arr=@_;
  print "f0: @arr\n";
}

my @arr=(1,2,3);
f0(@arr);
  

複数の配列を引数として渡す場合,困ったことになります.つまり,こういうプログラムです.

#!/usr/bin/perl -w
use strict;

sub f0{
  my (@arr1,@arr2)=@_;
  print "f0.arr1: @arr1\n";
  print "f0.arr2: @arr2\n";
}

my @a1=(1,2,3);
my @a2=(4,5,6);
f0(@a1,@a2);
  

実行結果はこうなります.

$ sam.pl
f0.arr1: 1 2 3 4 5 6
f0.arr2:
  

サブプログラムf0の引数として与えた二つの配列の全要素が,一つの配列@_に入るため,サブプログラムf0側では引数の切れ目がわからなくなるのです.その結果,f0に最初に指定した@arr1に全要素が入り,@arr2には何も入らない結果となりました.

main: @arr1=(1,2,3) @arr2=(4,5,6)
↓
@_=(1,2,3,4,5,6)
↓
f0:   @arr1=(1,2,3,4,5,6),@arr2=();
  

サブプログラムへ複数の配列を引数として渡す場合は,リファレンスを使います.

#!/usr/bin/perl -w
use strict;

sub f0{
  my ($arr1,$arr2)=@_; リファレンスはスカラ型で受取る
  print "f0.arr1: @$arr1\n"; もらったリファレンスを配列として扱う
  print "f0.arr2: @$arr2\n";
}

my @arr1=(1,2,3);
my @arr2=(4,5,6);
f0(\@arr1,\@arr2); 配列のリファレンスを渡す
  

実行結果はこうなります.

$ sam.pl
f0.arr1: 1 2 3
f0.arr2: 4 5 6
  

リファレンスが指し示す内容をサブプログラム中で書き換えると,元の値も書き換わります.注意しましょう.

#!/usr/bin/perl -w
use strict;

sub f0{
  my ($arr1,$arr2)=@_;
  print "f0.arr1: @$arr1\n";
  print "f0.arr2: @$arr2\n";
  $$arr1[0]='a'; #リファレンスの参照元を書き換える
  $$arr2[0]='b'; #リファレンスの参照元を書き換える
}

my @arr1=(1,2,3);
my @arr2=(4,5,6);
f0(\@arr1,\@arr2);
print "main.arr1: @arr1\n"; #リファレンスの参照元が書き換わる
print "main.arr2: @arr2\n"; #リファレンスの参照元が書き換わる
  

実行結果はこうなります.

$ sam.pl
f0.arr1: 1 2 3
f0.arr2: 4 5 6
main.arr1: a 2 3
main.arr2: b 5 6
  

上記プログラムは,配列のリファレンスを返す[]を使ってこのように書くこともできます.

#!/usr/bin/perl -w
use strict;

sub f0{
  my ($arr1,$arr2)=@_;
  print "f0.arr1: @$arr1\n";
  print "f0.arr2: @$arr2\n";
  $$arr1[0]='a';
  $$arr2[0]='b';
}

my $arr1=[1,2,3]; #$arr1は配列(1,2,3)のリファレンス
my @arr2=(4,5,6); #@arr2は配列(4,5,6)
f0($arr1,\@arr2); #$arr1はリファレンスなので\は不要
print "main.arr1: @$arr1\n"; #$arr1を配列として扱う
print "main.arr2: @arr2\n";