perlref - Perlのリファレンスとネストしたデータ構造
本ドキュメントはリファレンスに関するものです。 チュートリアルに関しては perlrefut を参照してください。
リリース 5 以前の Perl ではすべてのリファレンスはシンボリックでなければ ならなかったために、複雑なデータ構造を表現することが困難でした。 そしてシンボルテーブルのエントリーではなく変数を参照したいと望んだときも 困難であったのです。 Perl はシンボリックリファレンスを変数として使うことを簡単にしただけでなく、 任意のデータについて「ハード」リファレンスを持つことを可能としたのです。 任意のスカラはハードリファレンスを保持することができます。 配列とハッシュはスカラから構成されているので、あなたはいまや配列の配列、 ハッシュの配列、配列のハッシュ、関数のハッシュの配列等々を簡単に 組み立てることができるのです。
ハードリファレンスは賢く実際に参照されている数を管理していて、その数が 0 になれば自動的に解放を行ないます。 (自己参照や循環データ(cyclic data)にある値に対する参照カウントは、 ちょっとした手助けなしにはゼロにはなりません。 詳しくは Two-Phased Garbage Collection in perlobj を参照してください。) そのものがオブジェクトであるときには、デストラクタが動作します。 オブジェクトについてより詳しくは、perlobj を参照してください。 (ある意味では、Perl のすべてがオブジェクトですが、通常、 クラスパッケージ内で公に "bless" されているものへのリファレンスに対して、 この用語を用います。)
UNIX ファイルシステム上でのシンボリックリンクが単にファイルの名前を
持っているだけであるのと同様に、シンボリックリファレンスは変数の
名前を保持します。
*glob の記法は、シンボリックリファレンスの一種です
(シンボリックリファレンスは時折“ソフトリファレンス”と
呼ばれますが、そういう呼びかたをしないでください。
リファレンスは同義語を使わないでいてさえ混乱を招くのですから)。
対照的に、 ハードリファレンスはUNIXのファイルシステム上のハードリンクに 似ています。 ハードリンクはそれがなんの名前であるのかを気にせずに 基礎をなすオブジェクトにアクセスするために使われます。 以下の節にあるように“リファレンス”と言う言葉を形容なしに使った 場合、通常はハードリファレンスのことを指します。
Perlでリファレンスを使うのは非常に簡単です。 原則のオーバーライドが一つあるだけです。 Perl はリファレンス(referencing)やデリファレンス(defreferencing)を 暗黙に行うことはありません。 スカラがリファレンスを保持しているとき、それは常に単純なスカラとして 振る舞います。 勝手に配列や、ハッシュ、サブルーチンとして振る舞うようなことはありません。 デリファレンスをすることによって、自分で明示的に Perl に 教える必要があります。
リファレンスは幾つかのやり方で構築することができます。
変数、サブルーチン、値にバックスラッシュ演算子を使うことによる (これは C での & (アドレス) 演算子に似た働きをします)。 既にシンボルテーブルには変数へのリファレンスが存在していますから、 この方法は 別の リファレンスを作るものです。 しかし、シンボルテーブルのリファレンスがなくなったとしても、 バックスラッシュが返したリファレンスが存在することになります。 例をいくつかあげます:
$scalarref = \$foo;
$arrayref = \@ARGV;
$hashref = \%ENV;
$coderef = \&handler;
$globref = \*foo;
バックスラッシュ演算子を使って IO ハンドル(ファイルハンドルまたは ディレクトリハンドル)へのリファレンスを生成することはできません。 もっとも良く扱うリファレンスは型グロブに対するリファレンス(実際には シンボルテーブルのエントリである)でしょう。 後述する *foo{THING} 構文の説明を参照してください。 しかしながら、IO ハンドルであったものとして型グロブや型グロブの リファレンス(grobref)を使うこともできます。
名前の無い配列へのリファレンスは、大かっこを使って作ることができます:
$arrayref = [1, 2, ['a', 'b', 'c']];
ここでは、『「名前の無い 3 個の要素を持つ配列」を最後の要素として持つ
3 個要素の名前の無い配列』へのリファレンスを作っています。
(あとで述べる多次元構文を使って、これをアクセスすることができます。
たとえば、上記のようにした後では、
$arrayref->[2][1] が "b" となります。)
列挙リストに対するリファレンスを取るということは、大かっこを使うことと 同じではありません。 これはリファレンスのリストを生成することと同じなのです!
@list = (\$a, \@b, \%c);
@list = \($a, @b, %c); # same thing!
特殊な場合として、\(@foo) は @foo の内容へのリファレンスのリストを返し、
@foo 自身へのリファレンスは返しません。
これは %foo と似ていますが、キーのリファレンスがコピーに対するもので
ある点が異なります(これはキーが完全なスカラではなく
単なる文字列であるためです)。
名前の無いハッシュへのリファレンスは、中かっこを使って作ることができます:
$hashref = {
'Adam' => 'Eve',
'Clyde' => 'Bonnie',
};
無名ハッシュと配列のコンストラクタは、複雑な構造を作るために自由に
組み合わせることができます。
後述する多次元構文は、そのようなものに対しても使うことができます。
上記の値はリテラルですが、変数や式であってもかまいません。
Perl での代入演算は、(たとえ、local() や my() の中でも) コンパイル時の
宣言文ではなく、実行文だからです。
中かっこは、BLOCK を始めとして他のことにも使われますから、
開きの中かっこが BLOCK の開始でないことを Perl に教える
ために文の最初の中かっこの前に + や return をつけて、
曖昧さをなくすようにする必要がある場合があります。
このちょっとした余分な作業は、中かっこの使用に関連して
実際に使ってみる価値や覚えておくだけの価値があるでしょう。
たとえば、新しいハッシュを作って、それへのリファレンスを返す関数が欲しければ、 以下のような選択肢があります:
sub hashem { { @_ } } # silently wrong
sub hashem { +{ @_ } } # ok
sub hashem { return { @_ } } # ok
その一方で、以下のようにすることもできます:
sub showem { { @_ } } # ambiguous (currently ok, but may change)
sub showem { {; @_ } } # ok
sub showem { { return @_ } } # ok
先頭にある +{ や {; が、その式が実際には
ハッシュのリファレンスなのかブロックなのかの
曖昧さを除去するためにあります。
無名サブルーチンのへのリファレンスは、サブルーチン名の無い sub を使って
作ることができます:
$coderef = sub { print "Boink!\n" };
セミコロンに注意してください。
内部のコードが即座に実行されるのではないということを除けば、sub{} は、
宣言というよりもむしろ、do{} や eval{} のような演算子です(しかし、
eval("...") の中でなければ、何回その行を実行しようとも
$coderef は、同一の 無名サブルーチンをリファレンスすることになります)。
無名サブルーチンは my() 変数に関連するクロージャのように振る舞います。
つまり、変数はカレントのスコープの中においてレキシカルに見えます。
クロージャは、無名関数をある特定のレキシカルコンテキストで
定義した場合にたとえそのコンテキストの外側で呼び出されたとしても
定義されたときのコンテキストで実行されることを要求するという
Lisp の世界の概念です。
わかりやすく言えば、あなたがサブルーチンを呼び出すときと同じように、 サブルーチンを定義するときに引数を渡すという奇妙なやり方ということです。 あなたはこれでオブジェクト指向的性質を実現することも できます。 が、Perl はすでにこれとは異なる仕組みを提供しています -- perlobj を参照してください。
クロージャは eval なしにサブルーチンのテンプレートを記述する方法だという 考え方もできます。 以下に示すのは、クロージャがどのように動作するのかの例です。
sub newprint {
my $x = shift;
return sub { my $y = shift; print "$x, $y!\n"; };
}
$h = newprint("Howdy");
$g = newprint("Greetings");
# Time passes...
&$h("world");
&$g("earthlings");
出力はこうなります。
Howdy, world!
Greetings, earthlings!
ここで特に、無名サブルーチンの実行時には“my $x”がスコープの外にあるにも
かかわらず、$x が newprint() に渡された値を参照しつづけていることに
注意してください。
これがクロージャがクロージャたる由縁です。
これはレキシカル変数にのみ適用されます。 動的変数はこれまでと同じように動作します。 クロージャは、大部分の Perl プログラマーがそれを使いはじめるために トラブルをしょいこんでしまうような代物ではありません。
リファレンスはコンストラクタと呼ばれる特別なサブルーチンが返すようにして
いることが多くなっています。
Perlのオブジェクトは、自分がどのパッケージと関係を持っているかを
知っているものへのリファレンスでしかありません。
コンストラクタは、その関係付けをどのように行なうかを知っているという意味で、
特別なサブルーチンにすぎません。
単なるリファレンスとしてスタートし、オブジェクトといわれている間でも
通常のリファレンスであることに変わりはありません。
コンストラクタは、慣習的に new() と名前を付けられ、間接的に呼び出されます:
$objref = new Doggie (Tail => 'short', Ears => 'long');
以下のようにしてもかまいません。
$objref = Doggie->new(Tail => 'short', Ears => 'long');
use Term::Cap;
$terminal = Term::Cap->Tgetent( { OSPEED => 9600 });
use Tk;
$main = MainWindow->new();
$menubar = $main->Frame(-relief => "raised",
-borderwidth => 2)
適切な型のリファレンスはそういったリファレンスが存在するかのような文脈で行うと、 実際に存在するようになります。 デリファレンスについてはまだ話していないので、まだ例を示すことができません。
リファレンスは、*foo{THING} 構文として知られている 特殊な構文を使って生成することができます。 *foo{THING} はリファレンスを *foo の THING スロット(これは foo として知られる全てのものを保持するシンボルテーブルのエントリです)に 返します。
$scalarref = *foo{SCALAR};
$arrayref = *ARGV{ARRAY};
$hashref = *ENV{HASH};
$coderef = *handler{CODE};
$ioref = *STDIN{IO};
$globref = *foo{GLOB};
$formatref = *foo{FORMAT};
これら全ては *foo{IO} を除き、自己説明的です。
ファイルハンドル(perlfunc/open)、ソケット(perlfunc/socket と
perlfunc/socketpair)、ディレクトリハンドル(perlfunc/opendir)
として使われる IO ハンドルを返します。
過去のバージョンの Perl に対する互換性のために、
*foo{FILEHANDLE} は *foo{IO} の同義語ですが、5.8.0 からは
非推奨です。
警告が有効になっていれば、非推奨警告が出ます。
*foo{THING} は、スカラの場合を除いた特定の THING がまだ使われてい
ない場合には undef を返します。
*foo{SCALAR} は $foo がまだ使われていなかった場合には
無名スカラへのリファレンスを返します。
これは将来のリリースでは変わる可能性があります。
*foo{IO} は、Typeglobs and Filehandles in perldata にある
ファイルハンドルをサブルーチンに渡したり、あるいは逆に
サブルーチンから返すために、あるいは大きなデータ構造を格納する
ために用いられる *HANDLE 機構の代替です。
その不利な点は新しいハンドルをあなたのために作り出すことはしないと
いうことです。
有利な点は、型グロブの代入を使うよりも気をつかう必要があまりないということです。
(しかし、これはまだファイルハンドルとディレクトリハンドルを融合します。)
しかし、もし以下の例で行っているように、値を型グロブではなくスカラに
代入すると、起きることに対するリスクはありません。
splutter(*STDOUT); # pass the whole glob
splutter(*STDOUT{IO}); # pass both file and dir handles
sub splutter {
my $fh = shift;
print $fh "her um well a hmmm\n";
}
$rec = get_rec(*STDIN); # pass the whole glob
$rec = get_rec(*STDIN{IO}); # pass both file and dir handles
sub get_rec {
my $fh = shift;
return scalar <$fh>;
}
リファレンスの作り方はこれだけです。 ここまでくると、どこか参照のかなたへ行ってしまったデータを取り戻すために、 どうやってリファレンスを使うかを知りたいことでしょう。 基本的な方法がいくつかあります。
変数名やサブルーチン名の一部として識別子を置くところでは、適切な 型のリファレンスを持った単純スカラ変数でその識別子を 置き換えることができます:
$bar = $$scalarref;
push(@$arrayref, $filename);
$$arrayref[0] = "January";
$$hashref{"KEY"} = "VALUE";
&$coderef(1,2,3);
print $globref "output\n";
$arrayref[0] や $hashref{"KEY"} という形でしているの ではない ことが 大切です。 スカラ変数のデリファレンスは、いかなる key の検索よりも 前に 行なわれます。 単純スカラ変数より込み入ったものはすべて、 以下の 2 番か 3 番の方法が採られます。 しかしながら、「単純スカラ」には、この 1 番目の方法を再帰的に使っている 識別子も含まれます。 したがって、以下はは、"howdy" と出力します。
$refrefref = \\\"howdy";
print $$$$refrefref;
変数名やサブルーチン名の一部として識別子を置くところでは、適切な型の リファレンスを返す BLOCK を伴う識別子で置き換えることができます。 言い換えると、先の例は以下のように書くことができます:
$bar = ${$scalarref};
push(@{$arrayref}, $filename);
${$arrayref}[0] = "January";
${$hashref}{"KEY"} = "VALUE";
&{$coderef}(1,2,3);
$globref->print("output\n"); # iff IO::Handle is loaded
確かにこの場合には中かっこを付けるのはばかげたことかもしれませんが、 BLOCK には任意の式、特に添字を付けた式を入れることができます:
&{ $dispatch{$index} }(1,2,3); # call correct routine
単純な <$$x> の場合には中かっこが省略できるので、シンボルの デリファレンスを適当な演算子のように受け取って、その優先順位はどのくらいかと 悩む人があります。 しかし、もし演算子であれば、中かっこの代わりに、 普通の括弧が使えることでしょう。 そうではありません。 以下の違いを考えてみてください。 CASE 0 は、CASE 1 を短くしたものであり、CASE 2 を 短くしたものでは ありません:
$$hashref{"KEY"} = "VALUE"; # CASE 0
${$hashref}{"KEY"} = "VALUE"; # CASE 1
${$hashref{"KEY"}} = "VALUE"; # CASE 2
${$hashref->{"KEY"}} = "VALUE"; # CASE 3
CASE 2 もまた間違えやすいもので、%hashref という変数をアクセスするものです。 $hashref を仲介して、それが指すことになっているハッシュを デリファレンスしているものではありません。 それは、CASE 3 です。
配列の個々の要素を使う場合が増えると、2 番の方法を使うのが 煩わしくなってきます。 構文上の打開策として上記の 2 行は、以下のように書けます:
$arrayref->[0] = "January"; # Array element
$hashref->{"KEY"} = "VALUE"; # Hash element
$coderef->(1,2,3); # Subroutine call
矢印の左側には先行するデリファレンスを含めて、リファレンスを返す任意の式が
書けます($array[$x] は、$array->[$x] と同じでは ありません)。
$array[$x]->{"foo"}->[0] = "January";
これが、先の左辺値コンテキストで用いるとリファレンスが
存在するようになるというケースの一つです。
この文以前には、$array[$x] は未定義かもしれません。
その場合自動的にハッシュリファレンスと定義されて、{"foo"} が
検索できるようになります。
同じように $array[$x]->{"foo"} が配列リファレンスで定義されるので、
[0] をそこで探すことができます。
このプロセスは 自動有効化 (autovivification) と呼ばれます。
もう一つ。矢印は、括弧付きの添字の 間 では、省略することができますので、 上の例は、以下のように書けます:
$array[$x]{"foo"}[0] = "January";
通常の配列だけを使うように限定すれば、ちょうど C の多次元配列のように 使うことができます:
$score[$x][$y][$z] += 42;
ああ、そうだ、実際には全く C の配列と同じという訳ではありません。 C では、必要に応じて配列を大きくするなどということはできません。 Perl では、それができます。
リファレンスが、オブジェクトに対するものである場合には、参照されるものを アクセスするためのメソッドがあるはずで、オブジェクトのメソッドを 定義するクラスパッケージ内でなければ、そのメソッドを使うように した方が良いでしょう。 言い換えると、良識をもって、特別正当な理由がない限り、 オブジェクトのカプセル化を反古にしてはいけないということです。 Perl は、カプセル化を強要したりはしません。 私達は、全体主義者ではありません。 ただ、なにがしかの基本的な節度を期待しています。
文字列や数値をリファレンスとして使うと、上述したようにシンボリック リファレンスを生成します。 リファレンスを数値として使うと、メモリ内のストレージの位置の 整数表現を生成します。 これを利用して便利な唯一の状況は、二つのリファレンスを数値として 比較することで、同じ場所を参照しているかどうかを調べる場合です。
if ($ref1 == $ref2) { # cheap numeric compare of references
print "refs 1 and 2 refer to the same thing\n";
}
リファレンスを文字列として使うと、参照しているものの型
(perlobj で記述しているように、bless しているパッケージを含みます)と、
16 進数で表現された数値アドレスの両方を生成します。
ref() 演算子は、アドレス抜きで、リファレンスが示しているものの型だけを
返します。
この使い方の詳細と例については perlfunc/ref を参照してください。
bless() 演算子は、オブジェクトをオブジェクトクラスとして機能する
パッケージと結び付けるために使うことができます。
perlobj を参照してください。
デリファレンスの構文では常に目的とするリファレンスの型を
示すことができますので、型グロブをリファレンスと同じように
デリファレンスすることができます。
つまり、${*foo} と ${\$foo} は、どちらも同じスカラ変数を
示すことになります。
次の例に示すのは、文字列にサブルーチン呼び出しを埋め込む仕掛けです:
print "My sub returned @{[mysub(1,2,3)]} that time.\n";
ダブルクォートで囲まれた文字列中に @{...} が見つかると、その
文字列はブロックとして評価されます。
ブロックでは、mysub(1,2,3) の呼び出しを実行し、その結果に対する
無名配列へのリファレンスが作られます。
つまり、ブロック全体では、配列へのリファレンスを返すこととなり、
@{...} でデリファレンスされた後、ダブルクォートで囲まれた文字列の中に、
埋め込まれることになります。
このごまかしははっきりしない式にも有用です:
print "That yields @{[$n + 5]} widgets\n";
リファレンスはもし未定義であれば必要に応じて存在するようになると言いましたが、 もしリファレンスとして使われた値が既に定義されていたときにはどのように なるのか示していませんでした。 これはハードリファレンスでは ありません。 リファレンスとして使ったならそれはシンボリックリファレンスとして扱われます。 つまり、スカラの値は(おそらく)無名の値への直接のリンクではなく、 変数の 名前 として扱われます。
そのように働くと思われていることが多いものです。 ですからそう動作するのです。
$name = "foo";
$$name = 1; # Sets $foo
${$name} = 2; # Sets $foo
${$name x 2} = 3; # Sets $foofoo
$name->[0] = 4; # Sets $foo[0]
@$name = (); # Clears @foo
&$name(); # Calls &foo() (as in Perl 4)
$pack = "THAT";
${"${pack}::$name"} = 5; # Sets $THAT::foo without eval
これは強力で、かつ多少危険でもあります。 (最大限の注意をはらって) ハードリファレンスを使おうとした場合にも、 誤ってシンボリックリファレンスを使ってしまうような場合があるからです。 これを防止するには、
use strict 'refs';
と書いて、囲っているブロック内の残りの部分ではハードリファレンスのみが 許されるようにすることができます。 内側のブロックでは、以下のように書いて打ち消すこともできます:
no strict 'refs';
シンボリックリファレンスでは、パッケージ変数(局所化されていたとしても グローバル)だけを見ることができます。 (my() で宣言した) 静的なローカル変数は、シンボルテーブルに 存在しないのでシンボリックリファレンスでは参照することができません。 たとえば:
local $value = 10;
$ref = "value";
{
my $value = 20;
print $$ref;
}
これは、20 ではなく、10 と出力します。
local() は、パッケージで「グローバルな」、パッケージ変数に
影響するものです。
perl のバージョン 5.001 で、中かっこに囲まれたシンボリックリファレンスが よりクォートのように、ちょうどそれが文字列の中にあるかのように 振る舞うという新たな機能が読みやすさのために追加されました。
$push = "pop on ";
print "${push}over";
これは push が予約語であるにも関らず常に“pop on over”となります。 これはクォートの外であっても同様です。 ですから、
print ${push} . "over";
や
print ${ push } . "over";
でさえも同じ効果となります。 (これは Perl 4 が 空白無しの形式を許しているにも関らず、 Perl 5.000 では構文エラーとなります)。 この構造はあなたが strict refs を使っているときに、 シンボリックリファレンスであることを考慮 していません。
use strict 'refs';
${ bareword }; # Okay, means $bareword.
${ "bareword" }; # Error, symbolic reference.
同様に添え字付けのすべてが単一の語で行われているので、 同じルールをハッシュに対する添え字付けに使われる 任意の裸の単語に適用します。 ですから、
$array{ "aaa" }{ "bbb" }{ "ccc" }
の代わりに以下のように書けて:
$array{ aaa }{ bbb }{ ccc }
そして添え字が予約語であるかどうかを心配することはありません。 以下のようなことがしたいという珍しい場合には:
$array{ shift }
裸の単語でないようにさせる何かを追加することで予約語であるように 強制的に解釈させることができます。
$array{ shift() }
$array{ +shift }
$array{ shift @_ }
use warnings プラグマや -w スイッチは文字列が予約語として
解釈されたときには警告を発します。
しかし、あなたが小文字だけからなる単語を使った場合にはもはや警告されません。
なぜなら文字列は事実上クォートされているからです。
警告: このセクションは実験的機能を説明しています。 将来のバージョンにおいて、細かな点は予告なしに変更される可能性があります。
注意: 現在のユーザー見える形の擬似ハッシュの実装(配列の最初の要素を 奇妙な形で使うもの)は Perl 5.8.0 から非推奨となりました; Perl 5.10.0 からは 取り除かれて、この機能は別の方法で実装される予定です。 現在のインターフェースは醜いだけでなく、現在の実装は通常の配列とハッシュの 利用をかなり目立つ形で遅くしています。 "fields" プラグマインターフェースは利用可能なまま残ります。
5.005 のリリースから、通常ハッシュリファレンスが要求されるような コンテキストの一部において配列リファレンスが使えるようになりました。 これはそれが構造体のフィールドであるかのごとく シンボル名を使った配列要素のアクセスを可能にします。
これを行うためには、配列は余計な情報を持たなければなりません。 配列の最初の要素はフィールド名を配列の添え字にマッピングする ハッシュリファレンスでなければなりません。 例を挙げましょう:
$struct = [{foo => 1, bar => 2}, "FOO", "BAR"];
$struct->{foo}; # same as $struct->[1], i.e. "FOO"
$struct->{bar}; # same as $struct->[2], i.e. "BAR"
keys %$struct; # will return ("foo", "bar") in some order
values %$struct; # will return ("FOO", "BAR") in same some order
while (my($k,$v) = each %$struct) {
print "$k => $v\n";
}
存在しないフィールドに対してアクセスしようとした場合、Perl は
例外を発生します。
矛盾を避けるために、fields プラグマで提供される fields::phash() 関数を
常に使ってください。
use fields;
$pseudohash = fields::phash(foo => "FOO", bar => "BAR");
パフォーマンスを向上させるために、Perl は型付けされた オブジェクトリファレンスのためのフィールド名から配列添え字への変換を コンパイル時に行ってしまうこともできます。 fields を参照してください。
擬似ハッシュでキーの存在をチェックする方法は 2 つあります。
1 つめは exists() を使うことです。
このチェックは、指定されたフィールドに値がセットされたことがあるかどうかが
わかります。
これはこの意味で通常のハッシュの振る舞いと一致します。
例えば:
use fields;
$phash = fields::phash([qw(foo bar pants)], ['FOO']);
$phash->{pants} = undef;
print exists $phash->{foo}; # true, 'foo' was set in the declaration
print exists $phash->{bar}; # false, 'bar' has not been used.
print exists $phash->{pants}; # true, your 'pants' have been touched
2 つめは、最初の配列要素にあるハッシュリファレンスに exists() を
使うことです。
これは、キーが擬似ハッシュの有効なフィールドであるかをチェックします。
print exists $phash->[0]{bar}; # true, 'bar' is a valid field
print exists $phash->[0]{shoes};# false, 'shoes' can't be used
擬似ハッシュの要素に対する delete() はキーそのものではなく、キーに対応する
値だけを削除します。
キーを削除するには、最初のハッシュ要素から明示的に削除する必要があります。
print delete $phash->{foo}; # prints $phash->[1], "FOO"
print exists $phash->{foo}; # false
print exists $phash->[0]{foo}; # true, key still exists
print delete $phash->[0]{foo}; # now key is gone
print $phash->{foo}; # runtime exception
先に説明したように、関数がコンパイルされたときに可視なレキシカル変数に アクセスする無名関数はクロージャを作ります。 そういった変数に対するアクセスはシグナルハンドラであるとか Tk の コールバックのように、あとで実行されるときまで保持されてきた値を 取り出します。
巻数テンプレートとしてクロージャを使うことによって、同じような関数を たくさん作ることが可能になります。 ここで、あなたが様々色のためにフォントを変更する HTML を生成するような 色の名前のついた関数を必要としているとしましょう:
print "Be ", red("careful"), "with that ", green("light");
red() と green() といった関数は似通ったものになります。
これらを作り出すために、作ろうとしている関数の名前の型グロブに
クロージャを代入します。
@colors = qw(red blue green yellow orange purple violet);
for my $name (@colors) {
no strict 'refs'; # allow symbol table manipulation
*$name = *{uc $name} = sub { "<FONT COLOR='$name'>@_</FONT>" };
}
これで、それぞれの関数が別個に作成されます。
red(), RED(), blue(), BLUE(), green() のように呼び出すことが可能です。
このテクニックはコンパイル時間とメモリーの使用量を抑え、
同様にエラーを少なくします。
なぜなら、構文チェックはコンパイル時に行われるからです。
無名関数にある変数はすべて、適切なクロージャを作成するために重要なものです。
これはループの繰り返し変数に対する my の理由と同じです。
これはクロージャにプロトタイプを与えるための場所の一つでもあります。 生成する関数の引数にスカラコンテキストを与えようとするなら (おそらくはこの例に関してはあまり賢いやり方ではないでしょう)、 以下のように記述することができます:
*$name = sub ($) { "<FONT COLOR='$name'>$_[0]</FONT>" };
しかしながら、プロトタイプの検査はコンパイル時に行われるので、 この代入文はプロトタイプを使うには遅すぎるのです。 代入文のループ全体を BEGIN ブロックに置いてすべてを コンパイル時に行うようにすることでこれに対処することができます。
型を変更するようなレキシカル変数に対するアクセス -- 例えば先の例の
for ループのようなもの -- はクロージャに置いてのみ動作し、
一般的なサブルーチンでは動作しません。
一般的なケースでは、名前付きサブルーチンは適切にネストすることはなく、
(ネストするものが)無名関数であっても同じです。
これは、名前つきのサブルーチンはコンパイル時に一度だけ作成される
(そして外側のレキシカルに捕捉される)のに対し、無名サブルーチンは
'sub' 演算子が実行される毎に捕捉されるからです。
他のプログラミング言語にあるような、固有のプライベート変数を持った
ネストしたサブルーチンを使いたいのであれば、Perl ではちょっと
手間がかかります。
直感的にこうだと思うようなコーディングは、不可思議な警告
"will not stay shared" となるでしょう。
例を挙げると、以下の例はうまく動作しません:
sub outer {
my $x = $_[0] + 35;
sub inner { return $x * 19 } # WRONG
return $x + inner();
}
以下のようにするとうまくいきます:
sub outer {
my $x = $_[0] + 35;
local *inner = sub { return $x * 19 };
return $x + inner();
}
これで、inner() は outer() の中からのみ呼び出せるようになります。
なぜなら、クロージャ(無名関数)の一時変数に対する代入があるからです。
しかしこれを行ったとき、outer() のスコープからレキシカル変数 $x の
アクセスは通常通りです。
これは、通常 Perl ではサポートされていないような ある関数にローカルな関数を生成するときの興味深い効果です。
リファレンスをハッシュに対するキーとして使うことはできません。 それは文字列へ変換されてしまいます。
$x{ \$a } = $a;
キーをデリファレンスしようとするのであれば、それは ハードリファレンスには働きません。 そして、あなたがしようとしたことはできないでしょう。 次のような書き方をしたいと思うかもしれませんが、
$r = \@a;
$x{ $r } = $r;
動作しない keys() の代わりに、少なくとも本当のリファレンスとなる
values() を使うことができます。
標準モジュール Tie::RefHash はこれを扱いやすくするための 手段を提供しています。
ドキュメントの他に、ソースコードもためになります。 幾つかのリファレンスを使っている病理学的なサンプルは Perl の ソースディレクトリにある t/op/ref.t という退行テストにあります。
複雑なデータ構造を生成するためのリファレンスの使い方は perldsc と perllol を参照してください。 オブジェクトを生成するためのリファレンスの使い方は perltoot、perlobj、perlbot を参照してください。