Perl Hackers Hub

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

この記事を読むのに必要な時間:およそ 3.5 分

(1)こちら⁠2)こちらから。

Data::Dumperモジュール

リファレンスを使って複雑なデータ構造を作れるようになりましたが,このようなデータを表示するには,どうすればよいでしょうか?すでに説明したように,リファレンスを文字列として扱うとHASH(0x116360)のような文字列に変換されます。ですから,printの引数としてリファレンスを渡すと,このような文字列が表示されてしまいます。これでは役に立ちませんね。

Perlは,リファレンスを含むような複雑なデータ構造をわかりやすく表示するData::Dumperモジュールを備えています注6)⁠このモジュールはDumper関数をエクスポートします。Dumper関数は,渡されたデータ構造を人間が読める文字列に変換してくれます。

たとえば先ほど値を設定した$userinfoの内容を表示するには,次のようにします。

use Data::Dumper;
print Dumper($userinfo);

このコードの実行結果をリスト3に示します。

リスト3 Data::DumperモジュールのDumper関数を使って,複雑なデータ構造を表示する

1:$VAR1 = {
2:         'uid' => 1001,
3:         'env' => {
4:                    'HOME' => '/home/cond',
5:                    'TERM' => 'VT100'
6:                     },
7:         'name' => 'cond',
8:         'gid' => [
9:                    1,
10:                   200,
11:                   201,
12:                   203
13:                 ]
14:       };
注6)
Data::DumperモジュールはPerlのコアモジュールなので,自分でCPANからインストールする必要はありません。

無名サブルーチン

Perlは,名前を持たないサブルーチン..無名サブルーチンanonymous subroutineと呼びます..をサポートしています注7)⁠無名サブルーチンは次のように書きます。

sub { ..... }

まず先頭にキーワードsubを置き,その後ろにブレースで囲んだ文の並びを置きます。これは,普通のサブルーチン定義から,サブルーチン名を取り除いたものになっています。Perlは無名サブルーチンがあると,名前を持たないサブルーチンを定義して,それへのリファレンスを返してくれます。

次のコードでは,無名サブルーチンが生成されて,それへのリファレンスが変数$frefに代入されます。

$fref = sub { print "Hello, $_[0]\n"; };

この無名サブルーチンは,第1引数で指定した名前に対して,"Hello, XXXX"と呼びかけるメッセージを表示するものです。次のように書けば,"world"という引数を渡してこの無名サブルーチンを呼び出すので,"Hello, world"と表示されます。

&$fref("world");

また,配列リファレンスやハッシュリファレンスと同様に,->を使った書き方もできます(こちらの書き方のほうが好まれます)⁠

$fref->("world");
注7)
コードレフ(coderef)またはコードリファレンス(code reference)とも呼びます。

クロージャ

無名サブルーチンを生成する際には,その無名サブルーチンで使われるレキシカル変数(myで宣言された変数)の実体も,同時に封じ込められます。こうして生成された無名サブルーチンのことをクロージャclosureと呼びます。これだけの説明では何のことやらよくわからないと思いますので,例をもとに説明しましょう。

クロージャを返す関数greeting

リスト4では,greetingという関数(サブルーチン)を定義しています。この関数は引数を1個受け取って,それをmy変数$nameに代入します(2行目)⁠次に,4行目のreturn文で無名サブルーチンへのリファレンスを返します。返される無名サブルーチンは4~6行目で定義されていますが,実質的な処理は5行目のprintでメッセージを表示するだけです。

リスト4 関数greeting:あいさつをする関数を返す

1:sub greeting {
2:    my ($name) = @_; # この変数が封じ込められる
3:
4:    return sub {
5:        print "Hello, $name.\n";
6:    };
7:}
8:
9:my $john = greeting("John");
10:my $tom = greeting("Tom");
11:
12:$john->(); # Hello, John.
13:$tom->(); # Hello, Tom.

5行目のprintの引数の文字列に注目してください。この文字列では,変数$nameが変数展開されています。この$nameという変数は,2行目で宣言されているレキシカル変数(my変数)です。本来は,変数$nameは,関数greetingが実行されている間だけ存在し,関数から抜けた時点で消滅します。

しかし,5行目の文字列の中で変数$nameを使っているのでクロージャが生成されて,その中に変数$nameの実体が封じ込められます。関数greetingの実行が終了するとmy変数$nameは消滅しますが,無名サブルーチン(クロージャ)が存在する間,変数$nameの実体はそのクロージャの中に存在し続けることになります。

9行目では文字列"John"を渡して,関数greetingを呼び出しています。関数greetingは,変数$nameに"John"が代入された状態でクロージャを生成して返します。返されたクロージャは変数$johnに代入します。

同様に,10 行目では文字列"Tom"を渡して関数greeting を呼び出しています。今度は,変数$nameに"Tom"が代入された状態でクロージャが生成されます。返されたクロージャを変数$tomに代入しています。

関数greetingは,呼び出されるたびに新たにクロージャを生成して返す,ということに注意してください。そのため,9行目で生成されるクロージャと,10行目で生成されるクロージャとは,まったく別ものとなります。

12行目では,$johnに入っているクロージャを呼び出します。その結果,⁠Hello, John.」と表示されます。また13行目では$tomに入っているクロージャを呼び出します。今度は「Hello, Tom.」と表示されます。

著者プロフィール

近藤嘉雪(こんどうよしゆき)

読売新聞社,エル・エス・アイ ジャパン(株)などを経て,現在ヤフー(株)に勤務。エンジニアの教育などを担当している。

8080のマシン語からプログラミングを始め,大学の計算機演習でPL/Iを学び,8ビット用Cコンパイラ(LSI C-80)の開発にかかわる。その後,Perlに出会い,『Programming Perl』初版(赤ラクダ本)を翻訳する。

訳書に『プログラミングPerl 第3版』(通称:ラクダ本),『初めてのPerl 第6版』(通称:リャマ本)が(いずれもオライリー・ジャパン),著書に『yaccによるCコンパイラプログラミング』(絶版),『定本 Cプログラマのためのアルゴリズムとデータ構造,『定本 Javaプログラマのためのアルゴリズムとデータ構造』がある(いずれもソフトバンク クリエイティブ)。

URL:http://www.kondoyoshiyuki.com/
Twitter:@yoshiyuki_kondo

コメント

コメントの記入