アクセサ(4) Class::Accessor

CPANからのインストールも済んだので、Class::Accessorの使い方を勉強します。
といっても、使い方はとっても簡単です。Class::Accessor を継承すれば mk_accessors というクラスメソッドが使えるようになります。このメソッドに「属性名のリスト」を渡せば、自動的にその属性に対するアクセサ(getter/setter)を作ってくれます。
Class::Structの時に書いたコード を Class::Accessor を使って書き換えてみます。

package Person;
use strict;
use base qw(Class::Accessor);
Person->mk_accessors(qw(name age));
 
sub introduce {
    my $self = shift;
    print "I am " . $self->name();
    print ", " . $self->age() . " years old.\n";
}
 
package main;
use strict;
my $man = Person->new({name => "Somebody", age => 0});
$man->introduce();
 
$man->name("Taro");
$man->age(10);
$man->introduce();

ひとつずつ解説します。

use base qw(Class::Accessor);

base モジュールを使って Class::Accessor を継承しています。base モジュールは use する時に渡したモジュール名のリストを順番に require してから、リストを @ISA にセットしてくれます。多重継承もサポートしています。

Person->mk_accessors(qw(name age));

mk_accessors クラスメソッドを呼び出して、アクセサを生成しています。
qw は囲んだ文字列を空白で区切ったリストを返してくれる演算子でしたね。つまり、この場合 "name" と "age" という2つのアクセサメソッドが生成される事になります。

sub introduce {
    my $self = shift;
    print "I am " . $self->name();
    print ", " . $self->age() . " years old.\n";
}

アクセサで値を取得して表示しています。アクセサに何も渡さずに呼び出すと、値が取得できます。
文字列を連結する時は「.」(ドット)を使います。「+」(プラス)は数値の足し算を行なう演算子なので間違えないようにしましょう。他の言語だと「+」が文字列の連結演算子を兼ねている事が多いので気をつけなくては。

my $man = Person->new({name => "Somebody", age => 0});
$man->introduce();

コンストラクタ new は、Class::Accessor に宣言されているので継承できます。ハッシュのリファレンスを渡すと、各アクセサの初期値を決められます。

$man->name("Taro");
$man->age(10);
$man->introduce();

アクセサに値を渡して、値を設定しています。

実行結果は以下の通りです。

I am Somebody, 0 years old.
I am Taro, 10 years old.

ちゃんとアクセサが動作していますね。

ちなみに、「mk_ro_accessors」メソッドで「読み取り専用のアクセサメソッド」が、「mk_wo_accessors」メソッドで「書き込み専用のアクセサメソッド(ミューテータ)」が生成できます。

Class::Accessor によって生成されたアクセサメソッドを通じてオブジェクトの属性を取得/設定しようとすると、そのオブジェクトの get メソッド / set メソッドが経由されます。
これらのメソッドをオーバーライドする事で、アクセサメソッドの挙動を細かく制御できます。

Class::Accessor::Fast というモジュールもあります。こちらは基本的に Class::Accessor と同じ機能を持っているのですが、値の取得/設定の際に get/set メソッドを経由しないので Class::Accessor に比べて速く動作します。
上のコードのように、アクセサの挙動を特に変更しない場合は、Class::Accessor::Fast を使ったほうがいいですね。

アクセサの勉強はとりあえずこの辺りで終わりにします。まだまだ勉強しなくちゃいけない事が山積みですので。(^_^)

strict プラグマ

今までこの勉強日記に書いていたスクリプトには、strict プラグマを使っていませんでした。(プラグマ=use すると Perl の動作自体を変える事ができるモジュール)
短いコードばかりだったので、その必要もないかな、と思っていたのです……が、
iandeth. - Perl/CGI辞典 - 土井 毅さん 著 - にて use strict が推奨されていない件について

strict is your friend!!!!!
strict プラグマこそが、我々のミスを見つけてくれる、プログラマーの強力な味方です。「見通しの悪い複雑なスクリプト」を書いてしまう事への懸念は、すべてこの strict プラグマが晴らしてくれます。どんなにコードを書くときにも、かならずコードの先頭で、

use strict;

と書いておきましょう。

やはりどんなに短いコードでも use strict するべきなのですね。というわけで今後のぱるも日記では use strict を奨励していきます。(^_^)
strict プラグマを使うと、以下のような効果があります。

  • 宣言されていない変数が使えなくなる(use strict 'vars')
    • 全ての変数を「my」「our」「local」などで宣言するように強制する
      • (訂正) fbis さんのコメントによると「「local」はグローバル変数を局所化するだけのものなので「local $hoge」ってやってもstrictに怒られますよ。」との事です。確かにlocalは変数の局所化という意味でしたね。(^_^;)
    • スペルミスなどの typoコンパイル時にエラーになる
    • 変数がレキシカルかグローバルかわかりやすい
  • シンボリックリファレンスが使えなくなる(use strict 'refs')
    • 文字列をデリファレンスするだけでシンボリックリファレンス扱いになってしまうので、誤爆しやすい
    • シンボリックリファレンスは、その機能をよく理解していない限り使うべきではない
    • 「no strict 'refs'」で局所的に使えるようになる
  • 裸の文字列(bareword)が使えなくなる(use strict 'subs')
    • 裸の文字列とは頭に何も([$%@&*]が)ついていない識別子
    • その識別子がサブルーチンとして定義されていない場合は通常の文字列として扱われるが、それをエラーにする
    • サブルーチン呼び出しの typo を防ぐ

つまり、strict プラグマは「typo誤爆を防ぐ」効果があるモジュールです。気をつけていても typo はしてしまうものです。Perl の場合 typo してもコンパイル時にエラーにならないので、かなり厄介なバグになってしまいます。
ちょっとの制約を付ける事で typo のバグを防げるなら、そうするべきです。
ちなみに次期バージョンである Perl6 からは、最初から「use strict」されている状態になるそうです。

Ajaxイン・アクション欲しい!

プレゼント応募です。Perl は関係ないですね。(^_^;;)
AjaxJavaScriptXMLHttpRequestMicrosoft.XMLHTTP などを使って行なうブラウザ上での非同期通信です。ページの遷移が無い、使いやすいインターフェースが作れます。
JavaScript も面白いスクリプト言語です。無名配列や無名ハッシュ(JavaScript では配列リテラル、オブジェクトリテラル)、正規表現リテラルクロージャ演算子や組み込み関数、構文など、Perl と似ている部分が多いと思います。
最近 Perl をずっと勉強しているので、JavaScript を書こうとすると「var」の代わりに「my」を書いてしまいます。(笑) 「var」は JavaScript での変数局所化ですね。グローバル変数の宣言も var で行なうので my とは少しだけ性質が異なります。
さて、Perl の勉強に戻りましょう。(^_^)