perlref - Perlのリファレンスとネストしたデータ構造
本ドキュメントはリファレンスに関するものです。 チュートリアルに関しては perlreftut を参照してください。
リリース 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}
を除いて自己説明的です。
ファイルハンドル(open in perlfunc)、ソケット(socket in perlfunc と
socketpair in perlfunc)、ディレクトリハンドル(opendir in perlfunc)
として使われる 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()
演算子は、アドレス抜きで、リファレンスが示しているものの型だけを
返します。
この使い方の詳細と例については ref in perlfunc を参照してください。
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";
同様に、スカラへのリファレンスを返す式は ${...}
で
デリファレンスできます。
従って、上述の式は以下のように書けます:
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 から削除されました。 'fields' プラグマはまだ利用可能です。
先に説明したように、関数がコンパイルされたときに可視なレキシカル変数に アクセスする無名関数はクロージャを作ります。 そういった変数に対するアクセスは、シグナルハンドラや 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
ループのように、基本的に取り囲むレキシカルスコープからの
要素への別名 -- は無名サブルーチンにおいてのみ動作し、
名前付きサブルーチンでは動作しません。
一般的に言うと、名前付きサブルーチンは適切にネストすることはなく、
main パッケージスコープ内でのみ宣言されるべきです。
これは、名前つきのサブルーチンはコンパイル時に一度だけ作成されるので、 そのレキシカル変数は、親ブロックの最初の実行時から親レキシカルに 代入されるからです。 親スコープに 2 回目に入ると、レキシカルは再作成される一方、 ネストしたサブルーチンは古いものを参照したままです。
無名サブルーチンは、'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() が起動するときの 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 を参照してください。