NAME

perlref - Perlのリファレンスとネストしたデータ構造

注意

これはリファレンスに関するあらゆる側面に関する完全な文書です。 チュートリアルに関しては perlreftut を参照してください。

DESCRIPTION

リリース 5 より前の Perl ではすべてのリファレンスはシンボリックでなければ ならなかったために、複雑なデータ構造を表現することが困難でした-- そしてシンボルテーブルのエントリーではなく変数を参照したいと望んだときも 困難であったのです。 Perl はシンボリックリファレンスを変数として使うことを簡単にしただけでなく、 任意のデータについて「ハード」リファレンスを持つことを可能としたのです。 任意のスカラはハードリファレンスを保持することができます。 配列とハッシュはスカラから構成されているので、あなたはいまや配列の配列、 ハッシュの配列、配列のハッシュ、関数のハッシュの配列等々を簡単に 組み立てることができるのです。

ハードリファレンスは賢く実際に参照されている数を管理していて、その数が 0 になれば自動的に解放を行ないます。 (自己参照や循環データ(cyclic data)にある値に対する参照カウントは、 ちょっとした手助けなしにはゼロにはなりません; 詳しくは "Circular References" を参照してください。) そのものがオブジェクトであるときには、デストラクタが動作します。 オブジェクトについてより詳しくは、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};
    $globname  = *foo{NAME};    # "foo"
    $pkgname   = *foo{PACKAGE}; # "main"

これらのほとんどは自己説明的ですが、*foo{IO} は特に注目するに値します。 これはファイルハンドル("open" in perlfunc)、ソケット("socket" in perlfunc"socketpair" in perlfunc)、ディレクトリハンドル("opendir" in perlfunc)として 使われる IO ハンドルを返します。 過去のバージョンの Perl に対する互換性のために、 *foo{FILEHANDLE}*foo{IO} の同義語ですが、 一つの名前 IO を一貫して使うために非推奨です。 v5.8 から v5.22 の間の perl では、これは廃止予定警告を出していましたが、 それ以降ではこの廃止予定は撤回されました。

*foo{THING} は、スカラの場合を除いた特定の THING がまだ 使われていない場合には undef を返します。 *foo{SCALAR} は、$foo がまだ使われていなかった場合には 無名スカラへのリファレンスを返します。 これは将来のリリースでは変わる可能性があります。

*foo{NAME}*foo{PACKAGE} は例外で、リファレンスではなく文字列を 返します。 これらは、型グロブに代入されているものではなく、型グロブ自身のパッケージと 名前を返します。 従って、*foo=*Foo::bar の痕では、*foo は文字列として使われるときには "*Foo::bar" になりますが、*foo{PACKAGE}*foo{NAME} はそれぞれ "main" と "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";

循環参照

Perl では「循環参照」を作ることが可能で、これはメモリリークを引き起こします。 循環参照は次のように、二つのリファレンスが対外へのリファレンスを 含んでいるときに起こります:

    my $foo = {};
    my $bar = { foo => $foo };
    $foo->{bar} = $bar;

また、単一の変数でも循環参照を作ることができます:

    my $foo;
    $foo = \$foo;

この場合、この変数の参照カウントは決して 0 になることはなく、リファレンスは ガベージコレクションされることはありません。 これはメモリリークを引き起こします。

Perl のオブジェクトはリファレンスとして実装されているので、オブジェクトでも 循環参照を作ることが可能です。 それぞれのノードが親ノードと子ノードを参照している TreeNode クラスを 考えてみます。 親のあるノードは循環参照の一部となります。

「弱い参照」を作ることで循環参照を壊すことができます。 弱い参照はは変数に対する参照カウントを増やさないので、オブジェクトは スコープ外に出て破壊できるようになります。 Scalar::Util モジュールでエクスポートされる weaken 関数でリファレンスを 弱い参照にすることができます。

以下は最初の例をより安全にする方法です:

    use Scalar::Util 'weaken';

    my $foo = {};
    my $bar = { foo => $foo };
    $foo->{bar} = $bar;

    weaken $foo->{bar};

$foo から $bar へのリファレンスは弱い参照になります。 $bar 変数がスコープ外になると、ガベージコレクションされます。 次回 $foo->{bar}キーの値を見ると、undef になります。

この行動は離れたところから見ると混乱するかも知れないので、弱い山椒の 使用は慎重に行うべきです。 最初に スコープ外に出る変数のリファレンスを弱い参照にする必要があります。 そのように、長生きする変数は、スコープ外に出るまで想定されるリファレンスを 含んでいます。

シンボリックリファレンス

リファレンスはもし未定義であれば必要に応じて存在するようになると言いましたが、 もしリファレンスとして使われた値が既に定義されていたときにはどのように なるのか示していませんでした。 これはハードリファレンスでは ありません。 リファレンスとして使ったならそれはシンボリックリファレンスとして扱われます。 つまり、スカラの値は(おそらく)無名の値への直接のリンクではなく、 変数の 名前 として扱われます。

そのように働くと思われていることが多いものです。 ですからそう動作するのです。

    $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()
    $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() は、パッケージで「グローバルな」、パッケージ変数に 影響するものです。

あまりシンボリックではないリファレンス

中かっこに囲まれたシンボリックリファレンスはちょうどそれが文字列の中に あるかのように、識別子や変数名を式の残りから単純に分離するという働きが できました。 例えば、

    $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.

同様に、添え字付けのすべてが単一の語で行われているので、同じルールを ハッシュに対する添え字付けに使われる任意の裸の単語に適用します。 ですから、

    $hash{ "aaa" }{ "bbb" }{ "ccc" }

の代わりに以下のように書けて:

    $hash{ aaa }{ bbb }{ ccc }

そして添え字が予約語であるかどうかを心配することはありません。 以下のようなことがしたいという珍しい場合には:

    $hash{ shift }

裸の単語でないようにさせる何かを追加することで、予約語であるように 強制的に解釈させることができます:

    $hash{ shift() }
    $hash{ +shift }
    $hash{ 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 ではサポートされていないような、 ある関数にローカルな関数を生成するときの興味深い効果です。

後置デリファレンス文法

v5.20.0 から、リファレンスを使うための後置文法が利用可能になりました。 これは "Using References" で記述されているように振る舞いますが、印を 前置するのではなく、後置印とアスタリスクを使います。

例えば:

    $r = \@a;
    @b = $r->@*; # equivalent to @$r or @{ $r }

    $r = [ 1, [ 2, 3 ], 4 ];
    $r->[1]->@*;  # equivalent to @{ $r->[1] }

Perl 5.20 と 5.22 では、この文法は use feature 'postderef' で有効にされなければなりません。 Perl 5.24 から、利用可能にするのに feature 宣言は不要になりました。

後置デリファレンスは、ブロック(両面)デリファレンスが動作する場所ならどこでも どうさするはずです。 この文法により、完全に左から右に読み書きできるようにします。 以下の等価物が定義されています。

  $sref->$*;  # same as  ${ $sref }
  $aref->@*;  # same as  @{ $aref }
  $aref->$#*; # same as $#{ $aref }
  $href->%*;  # same as  %{ $href }
  $cref->&*;  # same as  &{ $cref }
  $gref->**;  # same as  *{ $gref }

特に、$cref->&*$cref->() と等価 ではない ことに 注意してください; 異なった目的を提供します。

グロブ要素は後置デリファレンス機能を通して展開できます:

  $gref->*{SCALAR}; # same as *{ $gref }{SCALAR}

配列とスカラの後置デリファレンスを文字列展開(ダブルクォートや qq 演算子)の 中で使うことは 可能 ですが、postderef_qq 機能が有効になっている 場合のみです。

後置リファレンススライス

配列やハッシュの値スライスも後置デリファレンス記法をとることができ、 以下のような等価物があります:

  $aref->@[ ... ];  # same as @$aref[ ... ]
  $href->@{ ... };  # same as @$href{ ... }

5.20.0 で追加され、 the Key/Value Hash Slices section of perldata に記述されている後置キー/値の組のスライスも想定通りに振る舞います:

  $aref->%[ ... ];  # same as %$aref[ ... ]
  $href->%{ ... };  # same as %$href{ ... }

後置配列と同様、後置値スライスデリファレンスも文字列展開(ダブルクォートや qq 演算子)の中で使うことは 可能 ですが、postderef_qq 機能が 有効になっている場合のみです。

リファレンスへの代入

v5.22.0 から、リファレンス演算子は代入できるようになります。 これは別名化操作を行い、左側で参照される変数名は右側で参照されるものへの 別名になります:

    \$a = \$b; # $a と $b は同じスカラを示す
    \&foo = \&bar; # foo() は bar() を意味する

この文法は use feature 'refaliasing' で有効にされなければなりません。 これは実験的であり、no warnings 'experimental::refaliasing' が 有効でない限り、デフォルトでは警告されます。

以下の型式は代入され、右側はスカラコンテキストで評価されます:

    \$scalar
    \@array
    \%hash
    \&sub
    \my $scalar
    \my @array
    \my %hash
    \state $scalar # or @array, etc.
    \our $scalar   # etc.
    \local $scalar # etc.
    \local our $scalar # etc.
    \$some_array[$index]
    \$some_hash{$key}
    \local $some_array[$index]
    \local $some_hash{$key}
    condition ? \$this : \$that[0] # etc.

スライス演算子とかっこは右側をリストコンテキストで評価します:

    \@array[5..7]
    (\@array[5..7])
    \(@array[5..7])
    \@hash{'foo','bar'}
    (\@hash{'foo','bar'})
    \(@hash{'foo','bar'})
    (\$scalar)
    \($scalar)
    \(my $scalar)
    \my($scalar)
    (\@array)
    (\%hash)
    (\&sub)
    \(&sub)
    \($foo, @bar, %baz)
    (\$foo, \@bar, \%baz)

右側の各要素は右側の型へのリファレンスでなければなりません。 配列 (および場合によっては my/state/our/local) を直接囲むかっこは、 配列の各要素を、右側のリファレンスになる対応するスカラへの別名にします:

    \(@a) = \(@b); # @a and @b now have the same elements
    \my(@a) = \(@b); # likewise
    \(my @a) = \(@b); # likewise
    push @a, 3; # but now @a has an extra element that @b lacks
    \(@a) = (\$a, \$b, \$c); # @a now contains $a, $b, and $c

この型式と local を組み合わせるのと、ハッシュのすぐ周りにかっこを置くのは 禁止されています (これが何をしたいかがはっきりしないからです):

    \local(@array) = foo(); # WRONG
    \(%hash)       = bar(); # WRONG

リファレンスと非リファレンスの代入は、 右側の値が左側の各要素に対して正しい型である限りにおいて、 リストの中と 3 項条件式で組み合わせられますが、 これは不明瞭なコードになります:

    (my $tom, \my $dick, \my @harry) = (\1, \2, [1..3]);
    # $tom is now \1
    # $dick is now 2 (read-only)
    # @harry is (1,2,3)

    my $type = ref $thingy;
    ($type ? $type eq 'ARRAY' ? \@foo : \$bar : $baz) = $thingy;

foreach ループは、そのループ変数にリファレンス生成子を取ることも できますが、その文法は以下のうち一つに、オプションとして逆スラッシュの後に my, state, our を置く形に制限されます:

    \$s
    \@a
    \%h
    \&c

かっこは許されません。 この機能は、配列の配列やハッシュの配列に特に有用です:

    foreach \my @a (@array_of_arrays) {
        frobnicate($a[0], $a[-1]);
    }

    foreach \my %h (@array_of_hashes) {
        $h{gelastic}++ if $h{type} eq 'funny';
    }

警告: 別名化はクロージャでは正しく動作しません。 内側のサブルーチンは eval からレキシカル変数への別名化をしようとすると、 別名化はその内側のサブルーチンの中でのみ見ることができ、 変数が宣言された外側のサブルーチンには影響を与えません。 このおかしな振る舞いは変更予定です。

Declaring a Reference to a Variable

Beginning in v5.26.0 から、my, state, our, local の後にリファレンス化演算子を 置けるようになりました。 この文法は、use feature 'declared_refs' を有効にしていなければなりません。 これは実験的なので、no warnings 'experimental::refaliasing' が 有効でない限りデフォルトで警告されます。

この機能は、次のものを:

    my \$x;
    our \$y;

以下と等価にします:

    \my $x;
    \our $x;

これは主に、リファレンスへの代入に使われます (前述の "Assigning to References" を参照してください)。 これはまた、バックスラッシュを宣言変数のリストのアイテムのように使えます:

    my ($foo, \@bar, \%baz); # equivalent to:  my $foo, \my(@bar, %baz);

警告: ハッシュキーとしてリファレンスを使わないこと

リファレンスをハッシュに対するキーとして使うことは(普通は)できません。 それは文字列へ変換されてしまいます:

    $x{ \$a } = $a;

キーをデリファレンスしようとするのであれば、それは ハードリファレンスには働かず、 そして、あなたがしようとしたことはできないでしょう。 次のような書き方をしたいと思うかもしれません

    $r = \@a;
    $x{ $r } = $r;

動作しない keys() の代わりに、少なくとも本当のリファレンスとなる values() を使うことができます。

標準モジュール Tie::RefHash はこれを扱いやすくするための 手段を提供しています。

SEE ALSO

ドキュメントの他に、ソースコードもためになります。 幾つかのリファレンスを使っている病理学的なサンプルは Perl の ソースディレクトリにある t/op/ref.t という退行テストにあります。

複雑なデータ構造を生成するためのリファレンスの使い方は perldscperllol を参照してください; オブジェクトを生成するためのリファレンスの 使い方は perlootut, perlobj を参照してください。