<"リファレンス">

リファレンス

C言語にはポインタという概念があった。Perlのリファレンスは、ポインタの発展形とでも言うべき物である。

あんまりありがたみがわからない例
rf.pl :
#!/usr/bin/perl
$re = 'nakami';
$im = \$re;
print "$im $$im \n";

結果:
$ ./rf.pl
SCALAR(0x814f618) nakami

rf.plの解説をする。
2行目で、変数$reに文字列"nakami"を代入した。その次の行では、変数$imに"\$re"なるものを代入している。 これはただの変数の代入ではなく、実際、次の行で$imを出力すると、何だかよくわからない文字列"SCALAR(0x814f618)"が出てくる。

実は、3行目で$reの頭に付いた"\"は、後に続くものの"リファレンス"を返す演算子なのだ。 リファレンスとは平たく言えば場所である。"SCALAR(0x814f618)"のカッコの中の記号は、 $reがメモリ上のどの場所にあるかを示す住所(アドレス)である。 ちなみに、前の"SCALAR"は、$reがスカラー変数であることを表わしている。 3行目"$im = \$re;"の意味は、「$imは$reと同じ場所を指し示す」ということになる。 これは、「以後$imを$reとして扱う」とほぼ同義である。完全に同義でないのは、$imの出力結果を見ても判るだろう。

では、$imを使って$reの中身を表示させるにはどうするか、だが、それは4行目の次を見れば良い。 $imに更に$を重ねて$$imとすると、これはちゃんと"nakami"を出力してくれる。 この記法は"${$im}"の省略形である。アドレスを${ }で囲うと、そのアドレスに存在するものにアクセスできる、と解釈すれば良いだろう。 この「リファレンスの指示先にアクセスする行為」を「デリファレンス」と呼ぶ。 ちなみに、${ }の$は、そのアドレスにあるものをスカラー変数として解釈することを表わす。 配列へのリファレンスも同様にして得ることができるが、これを配列として扱うには${ }ではなく @{ }としなければならない。

ちょっとありがたみがわかる例
rf2.pl :
#!/usr/bin/perl
$ton=$tin=$kan='well'; #初期状態は'元気'
if($name=$ARGV[0]){ #ちなみに、"#"の後はコメントと見なされます
    if($name eq 'ton'){$who = \$ton;}
    if($name eq 'tin'){$who = \$tin;}
    if($name eq 'kan'){$who = \$kan;}
}
$$who='sick'; #指定した者を'病気'にする
print "ton:$ton tin:$tin kan:$kan\n";

結果:
$ ./rf2.pl
ton:well tin:well kan:well
$ ./rf2.pl tin
ton:well tin:sick kan:well

リファレンスは、値を引き出すだけはでなく値を代入することもできる。というか、それが出来ないとあんまり役に立たない。 この例ではリファレンス$whoに対する処理が1行で済むのであまり効率は変わらないが、 $whoに対して何行にも渡る複雑な処理を施さなければならない場合、それを4~6行目の各ifブロック内に一々書き写す手間を省くことができる。

ちなみに、3行目のifの条件節内に代入文があるが、Perlでは(Cでも)条件節はその内部の式を実行した結果を評価する。 たとえば、今の場合は$name=$ARGV[0]を実行した後で$nameを評価する。$nameが文字列であるなら、その中身が 未定義値か空文字列""で無い場合に真と判断する。従って、このifは、 rf2.plに何らかの引数を与えたときに真となる。

>>リファレンスとスコープ

あるブロックの外で宣言したスカラー変数に、そのブロック内でmyをつけて宣言した変数のリファレンスを代入する。 この変数は明示的にローカルなので、ブロックを抜けた時点で破棄される。 しかし、破棄されるのはこの変数の「名前とアドレスの関係」だけで、名前だけが解放され、 アドレス上の値は誰かがそこへのリファレンスを保持している限りその場所に残りつづける。
たぶんこれは極めて重要な事だと思う。

accend->Perl->labnote->index page