はじめに
Perlの備忘録として書いてます。
前回はシンボルテーブルについて記載しました。今回は、変数の挙動をカスタマイズする tie について。
tie とは
Perlの変数は、通常は単なるデータの入れ物です。しかし、tie 関数を使うと、変数を特定のクラス(そのクラスのオブジェクト)に結びつけることができます。
これにより、変数へのアクセス(読み込み、書き込み、キーの確認など)を、特定のメソッド呼び出しにフックさせることが可能になります。「変数に見えるけれど、裏側でAPIを叩いている」といった実装も可能です。
実践:スカラー変数の拡張
最も単純なスカラー変数の tie を見てみましょう。
値を代入すると、その内容を標準出力にログとして表示する変数を作成します。
package LoggingScalar;
sub TIESCALAR {
my ($class, $value) = @_;
# 第2引数があれば初期値として利用する
return bless \$value, $class;
}
sub FETCH {
my $self = shift;
return $$self;
}
sub STORE {
my ($self, $value) = @_;
print "[LOG]: $value\n";
$$self = $value;
}
package main;
# 変数 $log_var を LoggingScalar クラスに紐付ける
tie my $log_var, 'LoggingScalar', "initial_value";
print $log_var . "\n"; # initial_value
$log_var = "hello"; # 出力: [LOG]: hello
print $log_var; # hello
-
TIESCALAR:tie時に呼ばれるコンストラクタ -
FETCH: 変数の値を読み取る時に呼ばれる -
STORE: 変数に値を代入する時に呼ばれる
これを利用すれば、代入するだけでファイルに永続化される変数や、常に現在時刻を返す変数などを作成できます。
実践:ハッシュ変数の拡張(継承の活用)
ハッシュや配列を tie する場合、すべてのメソッド(STORE, DELETE, EXISTS, FIRSTKEY...)を実装するのは大変です。
そこで、Tie::StdHash モジュールを継承します。これにより、挙動を変えたいメソッドだけをオーバーライドすればよくなり、実装コストが下がります。
ここでは、「存在しないキーにアクセスすると、自動的にデフォルト値を生成して保存する」ハッシュを作成してみます。
package AutovivifyHash;
require Tie::Hash;
# Tie::StdHash を継承することで、FETCH 以外のメソッドの実装を省略できる
@ISA = qw(Tie::StdHash);
sub FETCH {
my ($self, $key) = @_;
# 親クラスのメソッドを使って存在確認
unless (exists $self->{$key}) {
print "Generating default value for $key...\n";
$self->{$key} = "default";
}
return $self->{$key};
}
package main;
tie my %hash, 'AutovivifyHash';
print $hash{foo};
# 出力:
# Generating default value for foo...
# default
# 代入などの通常の操作は親クラス(Tie::StdHash)が処理してくれる
$hash{bar} = 123;
print $hash{bar}; # 123
補足:オブジェクトの取得と untie
tie は、裏側で生成されたオブジェクトを戻り値として返します。
また、紐付けを解除したい場合は untie を使用します。
# オブジェクトを受け取る
my $obj = tie my $scalar, 'LoggingScalar';
# $obj を通じて裏側のメソッドを直接呼ぶことも可能
# $obj->some_method();
# 紐付けを解除(通常の変数に戻る)
untie $scalar;
応用例
tie は、モジュール利用者に「直感的なインターフェース」を提供するために使われています。
-
DBMファイル: ディスク上のファイルをハッシュのように扱う(
DB_File,GDBM_Fileなど) - Configファイル: 設定ファイルを読み込んでハッシュとして見せる
-
プロセス間通信: 共有メモリを変数として見せる(
IPC::Shareable)
まとめ
-
tieを使うと、変数の操作をメソッド呼び出しに変換できる -
Tie::StdHashなどを継承すると、必要な機能だけをカスタマイズできて便利 - スカラー、ハッシュだけでなく、配列(
Tie::Array)やファイルハンドル(Tie::Handle)も作成可能 - 便利だが、通常の変数に比べてメソッド呼び出しのオーバーヘッドがあるため、パフォーマンスは注意
次回は、Perlの「ソースフィルタ」について記載します。