Perl Hackers Hub

第20回リファレンス入門(2)

前回の(1)こちらから。

デリファレンスのテクニック

ブレースを使ったデリファレンス

ここで、ブレースを使ったデリファンレンスの書き方を紹介しましょう。先頭に、何にデリファレンスするかを表す文字($や@など)を置き、その後ろにリファレンスを返す式をブレース{ }で囲んで置きます。たとえば、変数$arefに入っているリファレンスを配列としてデリファレンスするには、⁠@{$aref}」と書きます。

これは、先ほど紹介した「@$aref」と同じ意味です。ブレースを使った書き方では、ブレースの間に(単なる変数に限らず)任意の式を書くことができます。式は、正しいリファレンス値を返さなければなりません。

${$sref}     # スカラ変数をデリファレンス
@{&get_array_ref()} # 関数を呼び出すことも可能
${$x[2]}     # 配列の要素をデリファレンス

上記の1行目の${$sref}は、ブレースなしの書き方$$srefと同じ意味になります。しかし3行目の${$x[2]}は、ブレースを取り除いた$$x[2]とは違う意味になるので注意してください。なぜなら、$$x[2]は${$x}[2]と解釈されるためです。

図1を見てください。左側は${$x[2]}と書いた場合で、グレーの部分②が${$x[2]}を表しています。これは配列@xの添え字2にあたる要素①に入っているリファレンスを、デリファレンスしたものです。

図1 ${$x[2]}と$$x[2]の違い
図1 ${$x[2]}と$$x[2]の違い

これに対して$$x[2]と書くと、${$x}[2]と解釈されるので図1の右側のようになります。③の変数$xに入っているリファレンスを配列としてデリファレンスして、得られた配列の添え字2にあたる要素④を表します。

このようにブレースの有無によって、まったく別の意味になるので、注意しましょう。

->によるデリファレンス

配列、ハッシュ、サブルーチン(関数)のデリファレンスを行う際に、次に示すような「->」を使った書き方もできます。

  • $x->[3]は、$$x[3]を表す
  • $h->{key}は、$$h{key}を表す
  • $f->($param)は、&$f($param)を表す

また、⁠->」を連続して指定することもできます。たとえば次のようにすれば、疑似的に多次元配列や多次元ハッシュをエミュレートできます。

$x->[3]->[2]         # 多次元配列
$h->{'foo'}->{'bar'} # 多次元ハッシュ

実際には、次の例のように[ ]、{ }、( )は自由に組み合わせることができます。

$mix->[10]->{'abc'}

->の両側が[ ]、{ }、( )である場合には、->を省略できます。つまり多次元配列と多次元ハッシュをエミュレートする例は、次のように書くことができます。

$x->[3][2]
$h->{'foo'}{'bar'}

多次元配列のエミュレーション

今説明した記法を使って$x[3][2][5]のように書けば、あたかも多次元配列のように扱うことができます[4]⁠。これを->を省略しないで書くと、$x[3]->[2]->[5]となります。

ここで、$xと[3]の間には->がないことに注目してください。なぜなら->を省略できるのは、その両側に[ ]や{ }がある場合だけだからです。つまり次の2つはまったく別ものとなります。

  • $x[3][2][5]は、$x[3]->[2]->[5]を表す
  • $x->[3][2][5]は、$x->[3]->[2]->[5]を表す

これらの違いを図2をもとに説明しましょう。説明を簡単にするために、図2では添え字を2次元にして、$x[2][1]と$x->[2][1]の違いを示しています。

図2 $x[2][1]と$x->[2][1]の違い
図2 $x[2][1]と$x

図2の左側は$x[2][1]です。省略された->を補ってやると$x[2]->[1]になります。これは次のように扱われます。まず配列@xの添え字2の要素①(つまり$x[2])に入っているリファレンスを配列としてデリファレンスします。そして、得られた配列の添え字1の要素②が、$x[2][1]が表しているものです。

次に、図2の右側の$x->[2][1]を見てみましょう。こちらは->を補うと$x->[2]->[1]となります。つまり、まずスカラ変数$xに入っているリファレンス③を配列としてデリファレンスします。得られた配列の添え字2の要素④に入っているリファレンスを、配列としてデリファレンスします。そして得られた配列の添え字1の要素⑤が、$x->[2][1]が表しているものです。

多次元配列と要素の自動生成

Perlでは配列の大きさを宣言する必要はありません。配列の要素に値を代入すると、自動的に配列の領域が確保されます。たとえば次のコードを実行すると、配列@myarrayに領域が割り当てられます。

my @myarray;
$myarray[100] = 'hello';

多次元配列風の記法$x[2][1]に対して値を代入すると、同様に自動的に無名の配列やハッシュが生成されます[5]⁠。これを自動生成autovivificationと言います。

たとえば次のコードを実行すると、図3のように、配列@xの実体と2個の無名配列が生成されます。

図3 自動生成
図3 自動生成
my @x;
$x[2][1] = 100; # 無名配列A が生成される
$x[3][2] = 200; # 無名配列B が生成される

上記の2行目の代入演算子によって、配列@xの実体と無名配列Aが生成されます。そして、配列@xの添え字2の要素に、無名配列Aへのリファレンスが代入され、無名配列Aの添え字1の要素に100が代入されます。

次に3行目の代入演算子によって、無名配列Bが生成されます。そして配列@xの添え字3の要素に、無名配列Bへのリファレンスが代入され、無名配列Bの添え字2の要素に200が代入されます。

無名配列と無名ハッシュ

先ほどのリスト2では、次のようにして配列リファレンスを渡して関数compute_sumを呼び出していました。

my @tmp_array = (1, 3, 5, 7, 9);
print "Total: ", compute_sum(\@tmp_array), "\n";

ここでは、まず最初に配列@tmp_arrayを作成してから、そのリファレンスを取得して渡しています。しかし、@tmp_arrayのような配列をいちいち用意するのは煩雑ですし、名前を考えるのも面倒です。

無名配列

Perlは、名前を持たない配列..無名配列anonymous arrayと呼びます..を書くための記法を用意しています。要素の間にカンマを挟んで並べたものをブラケット[ ]で囲んでやると、名前を持たない配列を生成して、それへのリファレンスを返してくれます。

たとえば次のコードを実行すると、5個の要素を持つ無名配列が作成され、その無名配列へのリファレンスが変数$arefに代入されます図4⁠。

$aref = [1, 2, 3, 4, 5];
図4 無名配列
図4 無名配列

リスト2の最初の2行は、無名配列を使えば次のように書くことができます。

print "Total: ", compute_sum([1, 3, 5, 7, 9]), "\n";

こちらの書き方では、名前の付いた配列を作る必要がないうえに、関数compute_sumの引数に直接無名配列を書けるので、コードが簡潔になります。

また、無名配列を表す記法[1, 2, 3]とリスト(1, 2, 3)とを混同しないように注意しましょう。

無名ハッシュ

Perlは、名前を持たないハッシュ..無名ハッシュanonymous hashと呼びます..を書くための記法を用意しています。要素の間にカンマを挟んで並べたものを、ブレース{ }で囲むと、名前を持たないハッシュを生成して、それへのリファレンスを返します。また、ハッシュなので、要素は「キー、値」のペアで指定します。

たとえば次のコードは、キーがそれぞれone、two、threeである3つの要素を持った無名ハッシュを生成して、そのリファレンスを$hrefに代入します。

$href = { 'one', 1, 'two', 2, 'three', 3};

ハッシュと=>

ハッシュを書く際に、=>を使うことができます。=>のことを太い矢印thick arrowと呼びます。=>は基本的にはカンマと同じ意味で、=>の左にはキーを、右には値を書きます。前の例を=>を使って書くと次のようになります。

$href = {'one' => 1, 'two' => 2, 'three' => 3};

このように=>を使うと、キーと値の対応が明確になりコードが読みやすくなります。ですから、ハッシュを書く際には=>がよく用いられます。

また、=>の左側(キー)が、英数字と下線のみから成る文字列(先頭は数字以外)である場合には、クォートを省略できます。ですから、この例は次のように書けます。クォートがないのですっきりしていますね。

$href = {one => 1, two => 2, three => 3};

無名配列と無名ハッシュを組み合わせる

無名配列と無名ハッシュを自由に組み合わせることにより、複雑なデータ構造を表現できます。次の例は無名ハッシュを使って、UNIX/Linux風のユーザ情報を表現したものです。

my $userinfo = {
        name => $name,
        uid => $uid,
        gid => [1, 200, 201, 203],
        env => {
            HOME => $ENV{HOME},
            TERM => "VT100"
        }
};

ここでは、name、uid、gid、envという4つのキーを持った無名ハッシュを作り、そのリファレンスを変数$userinfoに代入しています。Perlでは、このようにハッシュを使ってレコードやオブジェクトを表現します。ハッシュのキーは、オブジェクトやレコードのフィールド名を表します。

ここでは、キーnameに対しては変数$nameを、キーuidに対しては変数$uidを、それぞれ値としてセットしています。$nameと$uidには、それぞれユーザ名とユーザIDが入っている、という想定です。

キーgidに対しては、1、200、201、203という4個の要素が入った無名配列へのリファレンスを、値としてセットしています。これは、ユーザが所属するグループID(複数も可)を想定しています。

キーenvに対しては、無名ハッシュへのリファレンスを値としてセットしています。フィールド名envが表すように、環境変数という想定です。無名ハッシュには、2つのキーHOMEとTERMがあり、それぞれ値は$ENV{HOME}、"VT100"になっています。

nameフィールドにアクセスするには、$userinfo->{name} のようにします。環境変数HOMEの値は$userinfo->{env}->{HOME}によって取得できます。

<続きの(3)こちらです。>

おすすめ記事

記事・ニュース一覧