2010年9月1日水曜日

Perl best practices[Perlベストプラクティス] 5章 変数 5.1~5.7


このエントリーをはてなブックマークに追加


可能な限りレキシカル変数(my)のみを使用する


コードの独立性が下がるから。
レキシカルでない組み込み変数で避けられないものは



$_, @ARGV, $AUTOLOAD, $a, $b


など。
しかし他のほとんどの組み込み変数は必要なく、代案が存在する。


パッケージ変数を使用しない


パッケージ変数



### mainパッケージ
# ・パッケージの宣言が行われない場合、ourで宣言されたパッケージ変数は、
# mainパッケージに属する。
# ・Perlには、グローバル変数は、存在せず、パッケージ変数と
# レキシカル変数しか存在しない。

print "パッケージ宣言のない場合はmainパッケージに属する\n";





  • パッケージ変数を使用すると、モジュールの内部状態を変更されるかもしれない。

  • 一般的に、モジュールのインタフェースで変数を使用するのは、悪いプラクティス(17章参照)



ローカル化


ローカル化によって、パッケージ変数の内容を一時的に変更することができる。
現在のスコープを抜けると、元の値に戻る。
ローカル化したときは、前のパッケージ変数の値ではなくundefが入る。
混乱しないように、初期値は明示的に代入しておく。


有名ではない句読点変数にはuse Englishで名前を付ける。


名前を付けなければ、滅多に使用されないコードなため、コメントを信用して、
内容チェックをスルーするかもしれない。


句読点変数のローカル化


IO処理において、句読点変数の値を変更する必要がある場合がある。
その場合は、無駄に影響を広げないためにローカル化する。


正規表現のマッチ変数を使用しない


use English qw( -no_match_vars );
で3つのマッチ引数が作成されないようにする。



  1. $PREMATCH  (または $`)

  2. $MATCH   (または $&)

  3. $POSTMATCH (または $')



マッチ変数は、正規表現が成功すると、追加情報として保存される。
マッチ変数はグローバルなので、どこかでマッチ変数が使用されていると、すべての正規表現のマッチが成功する度に、値が書き換えられる。このため、実行の効率が下がる。


また、自分がいざマッチ変数を参照するときに、中身が「どこの正規表現」で得られた結果なのか不明になる。異なるファイルにある正規表現である可能性すらある。


代わりにRegexp::MatchContextを使用する。
マッチ変数の代わりに、PREMATCH(),MATCH(),POSTMATCH()というサブルーチンが追加され、呼び出すことで、プレマッチ部、マッチ部、ポストマッチ部を得られる。

このとき、上記の値が変更される条件は、
(?p)というマーカが付いている正規表現かつ、マッチが成功したときではなく、マッチ変数が実際に使用されるとき。
このため、どこをデバックすれば良いかわかりやすいし、効率も良くなる。



use Regexp::MatchContext;

my ($name, $birth_year)
= $manuscript =~ m/(?p) (\S+) \s+ was \s+ born \s+ is \s+ (\d{4})/xms;

if ($name) {
print PREMATCH(),
qq{<born date="$birth_year" name="$name">},
MATCH(),
q{</born>},
POSTMATCH();
}



さらに、読み込み専用ではなく、substr形式の文字列が返されるので、MATCH()に代入すると、元の文字列が変更できる。
なので、正規表現による置換をわかりやすく記述することができる。



use Regexp::MatchContext;

if($html =~ m{(?p) <body> .* </body>}xms) {
PREMATCH() = $STD_HEADER; #標準ヘッダを<body>の前に設置
MATCH() = verify_body( MATCH() ); #コンテンツ
POSTMATCH()= '</html>'; #</body>の後ろは</html>だけにする
}





0 件のコメント:

コメントを投稿