可能な限りレキシカル変数(my)のみを使用する
コードの独立性が下がるから。
レキシカルでない組み込み変数で避けられないものは
$_, @ARGV, $AUTOLOAD, $a, $b
など。
しかし他のほとんどの組み込み変数は必要なく、代案が存在する。
パッケージ変数を使用しない
### mainパッケージ
# ・パッケージの宣言が行われない場合、ourで宣言されたパッケージ変数は、
# mainパッケージに属する。
# ・Perlには、グローバル変数は、存在せず、パッケージ変数と
# レキシカル変数しか存在しない。
print "パッケージ宣言のない場合はmainパッケージに属する\n";
- パッケージ変数を使用すると、モジュールの内部状態を変更されるかもしれない。
- 一般的に、モジュールのインタフェースで変数を使用するのは、悪いプラクティス(17章参照)
ローカル化
ローカル化によって、パッケージ変数の内容を一時的に変更することができる。
現在のスコープを抜けると、元の値に戻る。
ローカル化したときは、前のパッケージ変数の値ではなくundefが入る。
混乱しないように、初期値は明示的に代入しておく。
有名ではない句読点変数にはuse Englishで名前を付ける。
名前を付けなければ、滅多に使用されないコードなため、コメントを信用して、
内容チェックをスルーするかもしれない。
句読点変数のローカル化
IO処理において、句読点変数の値を変更する必要がある場合がある。
その場合は、無駄に影響を広げないためにローカル化する。
正規表現のマッチ変数を使用しない
use English qw( -no_match_vars );
で3つのマッチ引数が作成されないようにする。
- $PREMATCH (または $`)
- $MATCH (または $&)
- $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 件のコメント:
コメントを投稿