またPerl。
今日はリファレンスとサブルーチンだ。
リファレンスはポインタに似ているかも知れない。
まぁ使い道としては似てるわな。他のサブルーチンから値を書き換えたり、配列の配列を作るのに作ったり。
リファレンスの特徴は何のリファレンスでもスカラーであるということが1つある。
スカラーというのは$から始まる変数。すなわち、普通の値・文字列のことだ。
$ref1=\$_;
$ref2=\@myarr;
$ref3=\%myhash;
$ref4=\&mysub;
どう考えてもわかりにくい。こんなもん好き好んで使うものではないと思えてしまう。
ところで、配列は、スカラーの配列しか作れない。けど配列のリファレンスはスカラー。
だから配列のリファレンスの配列を作れば、配列の配列になると。なるほど…
@refs=(\@arr1,\@arr2);
print "$refs[0]->[1]\n";
print "${$refs[0]}[1]\n";
実際の使い方は、リファレンスとアロー演算子を組み合わせる方法が1つある。
リファレンスの指す配列の1番目が欲しければ->[1]、リファレンスの指すハッシュのキーが’smith’が欲しければ->{‘smith’}。
ここではリファレンス$refs[0]の指す配列の1番目だからこうなってる。
もう1つは、リファレンスを配列に戻して使う。
$refが、配列のリファレンスなら、@$ref、ハッシュのリファレンスなら%$refで表される。
さて、ここでは${$refs[0]}[1]となってるが、これは配列@{$refs[0]}の1番目という意味。Perlの配列はこうだよね。
@$refs[0]ではなくて@{$refs[0]}なのは解釈の順番がおかしくなるから。そんなときは{}で囲めばOK。
どっちでも好きな方を使えばいい。
もっとも$ref->[0]->[1]->{‘smith’}->[5]のようなものは、[]や{}に挟まれた->は省略してよいので、
$ref->[0][1]{‘smith’}[5]で構わない。だから、実は$refs[0]->[1]は$refs[0][1]でもOKです。
もちろん2つの方法を織り交ぜて、$$ref[0]->[1]->{‘smith’}->[5]、省略して$$ref[0][1]{‘smith’}[5]でもいい。
僕の感想では、ひたすらアロー演算子でつなげていく方がわかりやすい感じがします。
しかし、いちいち配列の配列を作るのに、中に入れる配列を作って、やるのはめんどくさい。
なので直接、配列のリファレンスを作る機能がある。
@refs=( [10,'あ'],[20,'う'] );
$hashref={'smith'=>[10,'foo'],'apple'=>[20,'bar']};
foreach(@refs){ foreach(@$_){ print "$_\n"; } }
print "$hashref->{'smith'}[0] : $$hashref{'smith'}->[1]\n";
()の代わりに配列なら[]、ハッシュなら{}を使うとリファレンスを直接作る。
だからこんな風に扱えるわけだ。
配列のリファレンスは値の束として使えそうな感じがするよね。
さて、サブルーチンだが、基本的な使い方はこんな感じ。
&foo('100','John');
&bar(1..10);
sub foo{
print "$_[0] : $_[1]\n";
}
sub bar{
foreach(@_){ print "$_\n"; }
}
使うときはサブルーチンの名前の前に&を付ける。
引数は配列で受け取る点が1つ特徴。@_という配列に入る。
だから$_[0]で0番目の引数が受け取れるわけ。
引数は配列であると開き直った例が2つ目。1..10は1,2,3,4,5,6,7,8,9,10と書くのと違いはないね。
ところで、サブルーチンにもリファレンスというものがある。
$ref1=\&bar;
@arr=(11..20);
&$ref1(@arr);
$ref2=sub{ print "$_[0] : $_[1]\n"};
&$ref2('100','John');
直接リファレンスも作れますよ。
C#の機能に、匿名デリゲートとかラムダ式とかあるけど、あれも直接デリゲートを作る機能だ。
サブルーチンのリファレンスの使い道はデリゲートと同じだと思うけど、オブジェクトが絡んだときの扱いは調べてない。
配列で受け取る機能の欠点は、引数として受け取れるのはスカラーだけということ。
配列を1つ受け取る時は、さっきみたいにいけるけどね。
あと、shift,popを利用して、配列の前、後からスカラーの引数を引っこ抜くという方法もある。これは裏技的な方法だな。
そうそう、引数の@_の中身は変更すると反映されてしまうよ。仮変数ではないので注意。
さて、ここで配列・ハッシュ・サブルーチンを引数に取るためにはどうすればいいかというと、
リファレンスにしてもらって受け取ると言うこと。
@arr=('foo','bar','hoge');
&foreachdo( \@arr , sub{ print "$_[0]\n"; } );
&foreachdo( [1..10] , sub{ print $_*$_ . "\n"; } );
sub foreachdo{
foreach( @{$_[0]} ){ &{$_[1]}($_); }
}
第一引数に配列のリファレンス、第二引数にサブルーチンのリファレンスを取るということ。
こんな風にいろいろ使えるわけ。
ただ、いちいち\を付けないといけないあたり直感的じゃないな。ちょっと残念。
いろいろ調べてたが、感想は、どうもめんどくさいということ。
けど、直接配列・ハッシュ・サブルーチンのリファレンスを作るのは便利な場合が多いかな。
ガリガリ使うのはいやだけど、適当な場所で使うと便利そう。
まぁしかし、多次元配列を配列のリファレンスの配列という方法で実現できるのはよい発見だったな。
どうするんだろうと悩んでたんだが、すっきり解決した。