PERLREF(1) USER COMMANDS PERLREF(1)
NAME
perlref - Perl のリファレンスとデータ構造のネスト
DESCRIPTION
Perl 4 では、複雑なデータ構造を表現するのは難しいことでした。
すべてのリファレンスはシンボリックでなければならず、シンボル
テーブルのエントリではなく、特定の変数を参照したいような場合
にも大変だったからです。 Perl 5 は、変数へのシンボリックリ
ファレンスを使い易くしただけではなく、どんなデータにも「ハー
ド」リファレンスが行なえるようにしました。 任意のスカラがハ
ードリファレンスを保持することができます。 スカラは、配列や
ハッシュの一部でもありますから、配列の配列、ハッシュの配列、
配列のハッシュ、関数のハッシュの配列といったものが簡単に作れ
るようになりました。
ハードリファレンスは賢く、実際に参照されている数を管理してい
て、その数が 0 になれば、自動的に解放を行ないます。 そのも
のがオブジェクトであるときには、デストラクタが動作します。
オブジェクトについてより詳しくは、perlobj manpage を参照して
ください。 (ある意味では、Perl のすべてがオブジェクトですが、
通常、クラスパッケージ内で公に "bless" されているものへのリ
ファレンスに対して、この用語を用います。)
ファイルシステム上でのシンボリックリンクが、単にファイルの名
前を持っているだけであるのと同様に、シンボリックリファレンス
は、変数の名前を保持します。 *glob の記法は、シンボリックリ
ファレンスの 1 種です。ハードリファレンスは、ファイルシステ
ム上のハードリンクに似ており、名前によらず、基本となる同一の
オブジェクトに到達する方法を与えるものです。
Perl では、「ハード」リファレンスは簡単に使えます。 これを
覆すような原則は、1 つのだけです。 Perl は、暗黙の参照や被
参照を行ないません。 スカラがリファレンスを保持しているとき
も、必ずスカラとして動作します。 明示的に被参照を指示しない
限り、そのスカラが魔法のように配列やハッシュとなることはない
のです。
リファレンスを作成する方法は、いくつかあります。
1. 変数、サブルーティン、値にバックスラッシュ演算子を使うこ
とによる。 (これは C での & (アドレス) 演算子に似た働き
をします。) 既にシンボルテーブルには変数へのリファレン
スが存在していますから、この方法は別のリファレンスを作る
ものであることに注意してください。 しかし、シンボルテー
ブルのリファレンスがなくなったとしても、バックスラッシュ
が返したリファレンスが存在することになります。 例をいく
つかあげます:
$scalarref = \$foo;
$arrayref = \@ARGV;
$hashref = \%ENV;
$coderef = \&handler;
Perl manpages Last change: Release 5.0 Patchlevel 00 1
PERLREF(1) USER COMMANDS PERLREF(1)
2. 名前の無い配列へのリファレンスは、大括弧を使って作ること
ができます:
$arrayref = [1, 2, ['a', 'b', 'c']];
ここでは、『「名前の無い 3 個の要素を持つ配列」を最後の
要素として持つ 3 個要素の名前の無い配列』へのリファレン
スを作っています。 (あとで述べる多次元構文を使って、こ
れをアクセスすることができます。 たとえば、上記のように
した後では、$arrayref->[2][1] が "b" となります。)
3. 名前の無いハッシュへのリファレンスは、中括弧を使って作る
ことができます:
$hashref = {
'Adam' => 'Eve',
'Clyde' => 'Bonnie',
};
名無しのハッシュと配列のコンストラクタは、複雑な構造を作
るために、自由に組み合わせることができます。 後述する多
次元構文は、そのようなものに対しても使うことができます。
上記の value はリテラルですが、変数や式であってもかまい
ません。 Perl での代入演算は、(たとえ、local() や my()
の中でも) コンパイル時の宣言文ではなく、実行文ですからで
す。
中括弧は、BLOCK を始め他のことにも使われますから、開き中
括弧が BLOCK の開始でないことを Perl に教えるために、文
の最初の中括弧の前に + や return をつけて、曖昧さをなく
すようにする必要がある場合があります。 この時折の余分な
仕事は、中括弧の使用に関する経済的、記憶的価値があると思
われます。
たとえば、新しいハッシュを作って、それへのリファレンスを
返す関数が欲しければ、以下のような選択肢があります:
sub hashem { { @_ } } # ちょっと間違い
sub hashem { +{ @_ } } # ok
sub hashem { return { @_ } } # ok
4. 名前の無いサブルーティンのへのリファレンスは、サブルーテ
ィン名の無い sub を使って作ることができます:
$coderef = sub { print "Boink!\n" };
セミコロンがあることに注意してください。 内部のコードが
即座に実行されるのではないという事実を除いて、sub{} は、
宣言というよりもむしろ、do{} や eval{} のような演算子で
Perl manpages Last change: Release 5.0 Patchlevel 00 2
PERLREF(1) USER COMMANDS PERLREF(1)
す。 (しかし、eval("...") の中でなければ、何回その行を
実行しようとも $coderef は、同一の無名サブルーティンを参
照することになります。)
こういったことを気にする方のため、現在のインプリメントで
は、local() 変数の浅い結び付きとなっています。 my() 変
数はアクセスできません。 これは、真のクロージャを疎外す
るものとなります。 しかし、(コンパイル時ではなく、) 実
行時の eval() を使えば、これに対応することができます:
{
my $x = time;
$coderef = eval "sub { \$x }";
}
通常は、(sub {} だけをつかったり、eval{} をも使う場合に
も) 新しい sub はグローバルな $x をアクセスすることがで
きるだけです。 しかし、実行時に eval() を使っているので、
呼ばれるごとに、新しいサブルーティンリファレンスを作り出
すだけではなく、グローバルな変数の代わりに、プログラム上
で自分より前に出てくる my() 変数をアクセスすることが許さ
れます。 一般には、アクセスされる $x は、新しい sub が
作られるごとに、違うものとなります。 このしくみでは、変
数は、動的な深い結び付きとなります。 (クロージャや、深
い結び付き、浅い結び付きというものが何かを知らなくても、
あまり悩まないでください。)
5. リファレンスは、コンストラクタと呼ばれる特別なサブルーテ
ィンが返すようにしていることが多くなっています。 Perl
のオブジェクトは、自分がどのパッケージと関係を持っている
かを知っているものへのリファレンスでしかありません。 コ
ンストラクタは、その関係付けをどのように行なうかを知って
いるという意味で、特別なサブルーティンにすぎません。 単
なるリファレンスとしてスタートし、オブジェクトといわれて
いる間でも通常のリファレンスであることに変わりはありませ
ん。 コンストラクタは、慣習的に new() と名前を付けます
が、そうしなければならないものではありません:
$objref = new Doggie (Tail => 'short', Ears => 'long');
6. 適切な型のリファレンスは、そういったリファレンスが存在す
るかのような文脈で被参照すると、実際に存在するようになり
ます。 被参照についてはまだ話していないので、例を示すこ
とができませんが。
リファレンスの作り方はこれだけです。 ここまでくると、どこか
リファレンスのかなたへ行ってしまったデータを取り戻すために、
どうやってリファレンスを使うかを知りたいことでしょう。 基本
的な方法がいくつかあります。
Perl manpages Last change: Release 5.0 Patchlevel 00 3
PERLREF(1) USER COMMANDS PERLREF(1)
1. 変数名やサブルーティン名の一部として識別子を置くところで
は、適切な型のリファレンスを持った単純スカラ変数で、その
識別子を置き換えることができます:
$bar = $$scalarref;
push(@$arrayref, $filename);
$$arrayref[0] = "January";
$$hashref{"KEY"} = "VALUE";
&$coderef(1,2,3);
$arrayref[0] や $hashref{"KEY"} という形で被参照している
のではないことが大切です。 スカラ変数の被参照は、いかな
る key の検索よりも「前に」行なわれます。 単純スカラ変
数より込み入ったものはすべて、以下の 2 番か 3 番の方法が
採られます。 しかしながら、「単純スカラ」には、この 1
番目の方法を再帰的に使っている識別子も含まれます。 した
がって、
$refrefref = \\\"howdy";
print $$$$refrefref;
は、"howdy" と出力します。
2. 変数名やサブルーティン名の一部として識別子を置くところで
は、適切な型のリファレンスを返す BLOCK を伴う識別子で置
き換えることができます。 言い換えると、先の例は以下のよ
うに書くことができます:
$bar = ${$scalarref};
push(@{$arrayref}, $filename);
${$arrayref}[0] = "January";
${$hashref}{"KEY"} = "VALUE";
&{$coderef}(1,2,3);
確かに、この場合には中括弧を付けるのは、莫迦げたことかも
しれませんが、BLOCK には任意の式、特に添字を付けた式を入
れることができます:
&{ $dispatch{$index} }(1,2,3); # 正しいルーティ
# ンの呼び出し
単純な $$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
Perl manpages Last change: Release 5.0 Patchlevel 00 4
PERLREF(1) USER COMMANDS PERLREF(1)
CASE 2 もまた、間違えやすいもので、%hashref という変数を
アクセスするものです。 $hashref を仲介して、それが指す
ことになっているハッシュを被参照しているいるものでは、あ
りません。 それは、CASE 3 です。
3. 配列の個々の要素を使う場合が増えると、2 番の方法を使うの
が、煩わしくなってきます。 構文上の打開策として、上記の
2 行は、
$arrayref->[0] = "January";
$hashref->{"KEY} = "VALUE";
のように書くことができます。
矢印の左側は、以前の被参照を含めて、リファレンスを返す任
意の式が書けます。 ($array[$x] は、$array->[$x] と同じ
ではありません。)
$array[$x]->{"foo"}->[0] = "January";
これが、先の左辺値コンテキストで用いると、リファレンスが
存在するようになる、というケースの 1 つです。 この文以
前には、$array[$x] は未定義かもしれません。 そうならば、
自動的にハッシュリファレンスと定義されて、{"foo"} が検索
できるようになります。 同じように、$array[$x]->{"foo"}
が配列リファレンスで定義され、[0] を探すことができます。
もう一つ。 矢印は、括弧付きの添字の「間」では、省略する
ことができますので、上の例は、
$array[$x]{"foo"}[0] = "January";
と書くことができます。 通常の配列だけを使うように限定す
れば、ちょうど C の多次元配列のように使うことができます:
$score[$x][$y][$z] += 42;
ああ、そうだ、実際には全く C の配列と同じという訳ではあ
りません。 C では、必要に応じて配列を大きくするなどとい
うことはできません。 Perl では、それができます。
4. リファレンスが、オブジェクトに対するものである場合には、
参照されるものをアクセスするためのメソッドがあるはずで、
オブジェクトのメソッドを定義するクラスパッケージ内でなけ
れば、そのメソッドを使うようにした方が良いでしょう。 言
い換えると、良識をもって、特別正当な理由がない限り、オブ
ジェクトのカプセル化を反古にしてはいけないということです。
Perl は、カプセル化を強要したりはしません。 私達は、全
体主義者ではありません。 ただ、なにがしかの基本的な節度
を期待しています。
Perl manpages Last change: Release 5.0 Patchlevel 00 5
PERLREF(1) USER COMMANDS PERLREF(1)
ref() 演算子が、リファレンスがどういった型のものを指している
かを、調べるために使うことができます。 perlfunc manpage を
参照してください。
bless() 演算子は、リファレンスをオブジェクトクラスとして機能
するパッケージと組み合わせるために使うことができます。 perl-
obj manpage を参照してください。
被参照構文では、常に目的とするリファレンスの「型」を示すこと
ができますので、型グロブをリファレンスと同じように被参照する
ことができます。 つまり、${*foo} と ${\$foo} は、どちらも同
じスカラ変数を示すことになります。
次の例に示すのは、文字列にサブルーティン呼び出しを埋め込む仕
掛けです:
print "My sub returned ${\mysub(1,2,3)}\n";
ダブルクォート文字列中に ${...} が見つかると、ブロックとして
評価されます。 ブロックでは、mysub(1,2,3) の呼び出しを実行
し、その結果に対するリファレンスがとられます。 つまり、ブロ
ック全体では、スカラへのリファレンスを返すこととなり、${...}
で被参照された後、ダブルクォート文字列の中に、はり込まれるこ
とになります。
シンボリックリファレンス
リファレンスは、もし未定義であれば、必要に応じて存在するよう
になると言いましたが、もしリファレンスとして使われた値が、既
に定義されていたときには、どのようになるのか示していませんで
した。 このような場合にリファレンスとして使ったなら、それは、
シンボリックリファレンスとして扱われます。 つまり、スカラの
値は、無名 (であるかもしれない) 値への直接のリンクではなく、
変数の「名前」として扱われます。
そのように働くと思われていることが多いものです。 それでそう
動きます。
$name = "foo";
$$name = 1; # $foo を設定
${$name} = 2; # $foo を設定
${$name x 2} = 3; # $foofoo を設定
$name->[0] = 4; # $foo[0] を設定
@$name = (); # @foo をクリア
&$name(); # &foo() を呼び出す(Perl 4 同様)
$pack = "THAT";
${"${pack}::$name"} = 5; # eval なしで $THAT::foo を設定
これは、非常に強力で、多少危険でもあります。 (最大限の注意
をはらって) ハードリファレンスを使おうとした場合にも、誤って
シンボリックリファレンスを使ってしまうような場合があるからで
Perl manpages Last change: Release 5.0 Patchlevel 00 6
PERLREF(1) USER COMMANDS PERLREF(1)
す。 これを防止するには、
use strict 'refs';
と書いて、囲っているブロック内の残りの部分では、ハードリファ
レンスのみが許されるようにすることができます。 内側のブロッ
クでは、
no strict 'refs';
と書いて、打ち消すこともできます。
シンボリックリファレンスでは、パッケージ変数だけを見ることが
できます。 (my() で宣言した) 静的なローカル変数は、シンボル
テーブルにありませんので、シンボリックリファレンスでは参照す
ることができません。 たとえば:
local($value) = 10;
$ref = \$value;
{
my $value = 20;
print $$ref;
}
これは、20 ではなく、10 と出力します。 local() は、パッケー
ジで「グローバルな」、パッケージ変数に影響するものです。
さらに学ぶために
明らかなドキュメントを除くと、ソースコードが多くのことを教え
てくれます。 多少不自然な、リファレンスの使用例は、Perl の
ソースディレクトリの t/op/ref.t レグレッションテストにもあり
ます。
Perl manpages Last change: Release 5.0 Patchlevel 00 7