2010年9月3日金曜日

Perl best practices[Perlベストプラクティス] 6章 制御構造 6.1~6.15


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


ポストフィックス形式のif文は制御フロー文にのみ使用



LOOP:
for my $mem (@mems) {
last LOOP if $mem f < 0;
}


next,last,redo,return,goto,die,croak,throwキーワードは、目立つ左端にくるように、if文を後ろにもってくる。


ポストフィックス形式のunless,for,while,untillを使用しない



  • 特にfor文は、ポストフィックス形式は使わない。

    • 反復子変数に$_を使う必要がある。

    • 評価式を簡単にはネストできない

    • 後からfor文が肥大化すると、ポストフィックス形式は無理がある。初めから使わない。





否定制御文(unless,untill)を使用しない



  • 拡張が難しい

    • 2重否定を理解するのが難しい

    • 否定制御文(unlessf)を否定演算子(!)に置き換えた場合、以降の条件をすべて反転させないといけない



  • もし否定制御文を使用する場合は、コードが見やすくなる場合だけにする

    • このとき、否定制御文の条件式は、肯定的なものにすること。





Cスタイルのループを使用しない




    • C言語のループは素直に読みにくい



以下のCスタイルのループは、読み手がロジックを解明する必要があるが、2番目のループは、やりたいことがそのまま書いてある。



for (my $n=4; $n<=$MAX; $n+=2) {
print $result[$n];
}

RESULT:
for my $n (4..$MAX) {
next RESULT if odd($n);#ベンチマークでパフォーマンスに問題ありならn%2を使用
print $result[$n];
}



また反復カウント用変数や条件式が2つ以上ある場合、または、反復カウンタ変数が線形に変化しない場合はwhile文を使う。(139ページ参照)


values関数から得られるリストは、エイリアスのリストである


エイリアスなので、実際のハッシュ値を書き換える。
ただし、delete関数だけは値のエイリアスでは不十分で、キーも知る必要がある。
この場合は、5章で解説されたハッシュスライスを使う。



my @unacceptable_words
= grep {$translation_for{$_} =~ m/ $PROFANITY /xms}
keys %translation_for;

delete @translation_for{@unacceptable_words};#スライスでdelete



反復にインデックスと値の両方が必要なときは、エイリアス化する



use Data::Alias;

for my $agent_num (0..$#operatives) {
alias my $agent = $operatives[$agent_num];

if($on_disavowed_list{$agent}) {
$agent = '[DISAVOWED]'; #エイリアス化してないと、ここでインデックスが必要になる
}


ハッシュの場合も同じ手法を用いる。
しかしeach関数はこの手法は仕えない。each関数で返される値は、ハッシュ値のエイリアスではなくコピーである。


非レキシカルループ反復子



my $client;

SEARCH:
for $client (@clients) { #forスコープ
last SEARCH if $client->holding();
}

if ($client) {#forの反復カウンタは常に破棄されるので、取得は不可能
$client->resume_conversation();
}



for文の$clientは、forのスコープで新しくこっそり作られたレキシカル変数であり、その前の$clientとは関係ない。ここで、for my $clientとしていれば、読み手に分かりやすく伝えることができる。(もちろん違う名前のほうがいい)


リストからリストの生成するには、mapを使用する


ある配列の要素を2乗して新しい配列に、反復で一つずつpushするコードでは、pushする度にメモリの再割当てが必要になる。
しかしmapは、事前に必要な要素数を把握する。(1つの要素から複数の要素を生成する場合は別)
またmapは、高速なCコードで処理される。


リスト値の検索はmapかfirstを使う


forの代わりに使うと、理解しやすい効率的なコードになる。


変換先と変換元の配列が同じ場合はmapではなくforを使う


mapは追加メモリを割り当てたあとに、一時的に保持していたリストを代入するが、forは変換元リストの既存のメモリを再利用できる。


複雑なマッピング


複雑な反復にコードが肥大化したときは、関数に避けて、単純なmap式から呼び出す。


リスト関数で$_を変更しない


$_はエイリアスなので、もとの値が変更されてしまう。分かりにくいコードになる。





0 件のコメント:

コメントを投稿