2013年08月02日の日記、「続・初めてのPerl」7の5
JavaScriptでクロージャのことは理解したと思ったけど思ってただけだった;
「続・初めてのPerl」の第7章のセクション5の出来事です。
自分の頭の整理も兼ねて、もし誰かの役に立てば。

以下、ソースコードです。
わかりやすくするために、コメントと記述順を変えました。
#! /usr/bin/perl

# ディレクトリのサイズを計算するプログラム

use strict;
use warnings;
use File::Find;

# サイズを知りたいディレクトリ名の配列
my @dirs = qw( test1dir test2dir test3dir );

# 各ディレクトリとそれに対する2つの関数(ファイルサイズ加算とGetter)をハッシュに登録する
my %subs;
for my $dir (@dirs) {
# 下方で定義している関数を呼び出す。
my ($callback, $getter) = create_callbacks_sum_size();
$subs{$dir}{CALLBACK} = $callback; # ファイルサイズ加算関数
$subs{$dir}{GETTER} = $getter; # Getter
}

# 各ディレクトリを調査する(ファイルの探索はFile::Find::findにおまかせ)
for my $dir (keys %subs) {
# ファイルを見つけてはCALLBACK関数に渡す。つまりファイルサイズ加算している。
find($subs{$dir}{CALLBACK}, $dir);
}

# 結果を表示する
for my $dir (sort keys %subs) {
my $sum = $subs{$dir}{GETTER}->(); # ディレクトリサイズ取得
print "$dir has $sum bytes\n";
}

# 2つのクロージャのリファレンスを配列にセットして返す関数定義
sub create_callbacks_sum_size {
# クロージャされる変数。(ディレクトリ内のサイズを保持する)
my $total_size = 0; # 以下の2つのクロージャで使用する変数の初期化
return (
# クロージャその1:ファイルのサイズを $total_size に加算する。
sub { $total_size += -s if -f ; },
# クロージャその2:$total_size を返す。
sub { return $total_size; },
);
}

上記のプログラムで create_callbacks_sum_size が返している関数(のリファレンス)がそれぞれクロージャです。
このサンプルでは2つ返したいので配列にセットして返してますけど。
なにをクローズしているかというと $total_size です。
クロージャ、クローズとかいってますけど、要は内包しているってことです。
なにがつまづくって $total_size は create_callbacks_sum_size関数が終わったら使い捨てられそうなのに使い続けられるからです。
なにから使われるというと、create_callbacks_sum_size関数が作った2つの関数(クロージャ)でです。
つまり、$subs{$dir}{CALLBACK}にセットした関数と$subs{$dir}{GETTER}にセットした関数は生きているからです。

この感動伝わりますかね?w
Perlはオブジェクト指向プログラムも作れるのでクラスとかフィールドとかメソッドとかいうのでこんなの惑わないのかもしれないけど、まだそこまで行ってないので感動なのです。
[PR]
by redchant | 2013-08-02 23:08 | 日記
<< 2013年08月03日の日記、... 2013年07月24日の日記、... >>