型グロブとリファレンス
というわけで、型グロブとリファレンスについて勉強します。型グロブ「*hoge」は「$hoge」や「@hoge」や「%hoge」など同じ名前で違う種類の変数の総称でしたね。
型グロブにハッシュのように *変数名{型名} とアクセスすると、その型の変数へのリファレンスを得る事ができます。型名のところに書けるものは以下の通りです。
{SCALAR} | スカラー | $ |
{ARRAY} | 配列 | @ |
{HASH} | ハッシュ | % |
{CODE} | コード | & |
{GLOB} | 型グロブ | * |
{IO} | 入出力 | (不明) |
{FILEHANDLE} | {IO}と同じ意味 |
使ってみます。
# refglob.pl
our $animal = "dog";
our @animal = ("cat", "lion", "tiger");
our %animal = (name => "cow", color => "white and black");
my $scalarref = *animal{SCALAR}; # \$animal と同じ意味
my $arrayref = *animal{ARRAY}; # \@animal と同じ意味
my $hashref = *animal{HASH}; # \%animal と同じ意味
print "$$scalarref\n";
print "@$arrayref\n";
print $hashref->{name}, " is ", $hashref->{color}, "\n";
まず、$animal と @animal と %animal をそれぞれ宣言します。そしてそれぞれのリファレンスを取得して表示しています。
この何が便利かというと、例えば扱う型が実行時にしかわからないプログラムを書く時に便利との事。
また、型グロブに型グロブを代入すると別名にする事ができましたが、型グロブにリファレンスを代入すると、その値がコピーされます。代入先は値の型によって自動判別されるようです。
# refglob2.pl
our $fruit = "apple";
our @fruit = ("banana", "orange", "lemon");
sub show_fruits() { print "$fruit\n@fruit\n\n"; }
show_fruits();
# スカラーのリファレンスを型グロブに代入
*fruit = \"grape";
show_fruits();
# 配列のリファレンスを型グロブに代入
*fruit = ["mango", "pine", "kiwi"];
show_fruits();
実行結果です。
apple banana orange lemon grape banana orange lemon grape mango pine kiwi
\"grape" は "grape" (スカラー値)へのリファレンスですから、型グロブ *fruit に代入すると $fruit が上書きされます。
[……] は無名配列へのリファレンスを生成する構文ですから、型グロブ *fruit に代入すると @fruit が上書きされます。
面白いですね。
ちなみに、リファレンスがどの型の値を参照しているかを調べるには ref 関数を使えばいいようです。「perldoc -f ref」の内容を引用します。
ref EXPR ref Returns a non-empty string if EXPR is a reference, the empty string otherwise. If EXPR is not specified, $_ will be used. The value returned depends on the type of thing the reference is a reference to. Builtin types include: SCALAR ARRAY HASH CODE REF GLOB LVALUE
もしリファレンスでなければ空の文字列を返し、リファレンスならば参照している物の型を表す文字列を返すようです。
# ref8.pl
my @refs = (
"string", # スカラー
\"string", # スカラーのリファレンス
123, # スカラー
[123, 456, 789], # 配列のリファレンス
{ id => "palmo" }, # ハッシュのリファレンス
sub { print "test!"; }, # 関数のリファレンス
\\1, # リファレンスのリファレンス
);
for (@refs) { print ref, "\n"; }
ref は $_ をデフォルトで受け取るようなので、引数を省略してみました。実行結果です。
SCALAR ARRAY HASH CODE REF
種類に沿った文字列が表示されました。リファレンスではないスカラー値は空文字列になっています。空文字列は偽ですから、if 文などで使えばリファレンスかどうかを判定できますね。