文字列の変数展開 文字列デリミタ4つのルール
- 変数を展開する場合は、2重引用符。
- 展開しない場合は、単一引用符。
- 単一引用符を文字列として扱いたい場合は、q{}を使用する。
- {を文字列として扱いたい場合は、q[]とする。
関連する文字列が並んでいる場合は、読み難いので、一つのルールで統一する。
my $title = 'Perl Best Practices';
my $publisher = q{O'Reilly};
my $end_of_block = '}';
my $closing_delim = q['}];
my $citation = "$title ($publisher)";
#以下に修正
my $title = q[Perl Best Practices];
my $publisher = q[O'Reilly];
my $end_of_block = q[}];
my $closing_delim = q['}];
my $citation = qq[$title ($publisher)];
空の文字列に"",''を使用しない
以下を使用のこと。
$error_msg = q{};
1文字の文字列
スペースやタブは
$a = q{ };
$b = "\t";
とすること。
リテラルの引用符も美しくないので、q{}を推奨。
名前付きエスケープを使用する。
Perlが表現できない文字は、数値のエスケープ(バックスラッシュとそれに続くASCII値を””で囲んだもの)で表せるが、use charnamesプラグマを用いて、名前付きエスケープを使用すること。
use charnames qw( :full);
$escape_seq = "\N{DELETE}\N{ACKNOWLEDGE}\N{CANCEL}Z"; # "\177\006\030z"
マジックナンバーはReadonlyで定数化する(use constantを使用しない)
定数はすべて大文字にし、定数名と値は=>(ファットコンマ)で見やすくする。
use Readonly;
Readonly my $BOOK_NUMBER => 42;
空文字q{ }を定数化すると便利。
なぜconstantを使用しないのか
use constantで作成されるのは裸のワードなので、定数が展開されない。
以下はReadonlyを使用した場合。
$msg = <<"END_MSG";
$BOOK_NUMBER
END_MSG
$title{$BOOK_NUMBER}
もっとも重要なことは、
レキシカルスコープをもつ定数を実行時に生成できること。
EVENT:
while (1) {
use Readonly;
Readonly my $EVENT => get_next_event();
last $EVENT if not defined $EVENT;
print "$EVENT\n";
}
8進数は組み込み関数octを使用する。
0で始まる整数で8進数を表現しない。
長い数字は桁区切りする
Perl5.8以降では、数字の間にアンダーバーを挿入することができる。(前versionは3桁区切りのみ)
$US_GDP = 10_990_000_000_000;
複数行の文字列は、\nで明示的に改行する
$usage = "Usage: aaaaa\n"
."bbbbb\n"
;
この\nを書かないで、
$usage = "Usage: aaaaa
bbbbb";
と文字列を折り返しても暗黙的に改行されるが、読みにくい。さらにインデントが左端による。
文字列が3行以上ならヒアドキュメントを使用する。
$Usage =<<"END_USAGE";
すきな文字列記述
END_USAGE
ヒアドキュメントのインデント問題
ヒアドキュメントはインデントが左端になってしまう。
定義済み変数かサブルーチン(ゼアドキュメント)にファクタリングする。
use Readonly
Readonly my $USAGE => <<'END_USAGE';
好きな文字列
END_USAGE
実行時に値を決定したい場合はサブルーチンを使う。
sub build_usage{
my($prog_name, $file_name) = @_;
return <<"END_USAGE";
$prog_name $file_name
END_USAGE
}
ヒアドキュメントのターミネータ
ラベルを見つけやすくするように、頭にENDを付ける。
ヒアドキュメントの引用符
- <<のあとのラベルを単一引用符で囲むと、変数は展開されない
- 2重引用符で囲むと変数が展開される
- 引用符を使わない裸のラベルでは、2重引用符と同じ結果が得られるが、使用しないこと
裸のワードを使用しない。
use strict qw( subs )で使用を禁止する。
裸のワードは引数なしのサブルーチンと名前が被る。
ファットコンマ
- ハッシュを生成する際に、=>を使用すれば、キーを引用符で囲む必要がない。
- =>の外観は、値の移動や変化の印象を与え易いが、動作の解釈に誤解を与えることもあり、ハッシュエントリや名前付き引数、その他の名前と値の組、のときのみ使用したほうが混乱しない。
文の順序付けはコンマではなく、doブロックを使う
- スカラーコンテキストでは、コンマは順序付け
- リストコンテキストでは、コンマはセパレータ
- 役割が2つあるのは混乱するので、順序付けにはdoブロックを使う。
C言語のforループのように、
for ($min=0, $max=$#samples, $found_target=0; $min<=$max) {
#略
}
と書いた場合、C言語と同じく、コンマは弱いセミコロンのような働きをし、順序付けを行う。
これはdoブロックで以下のようになる。
for (do{$min=0; $max=$#samples; $found_target=0;}; $min<=$max) {
#略
}
この場合は、そもそも初期値を指定しているdoブロックの中身をforの前に書いておく方がもっと良い。
優先度の高いブールと低いブールを混在させない
- 優先度の低いand,notはいっさい使用しない。
- orだけは、組み込み関数の代案を指定するために使用する。(or croak "...";など)
next CLIENT if not $finished || $result < $MIN_ACCEPTABLE; #これは以下のどれになるか
next CLIENT if (not $finished) || ($result < $MIN_ACCEPTABLE);#期待しているのはコレ
next CLIENT if not ($finished || $result < $MIN_ACCEPTABLE);#実際はコレ
リストは括弧で囲む
コンマは代入より優先順位が低いので、リストは常に括弧で囲む。
リストのメンバの評価には、any()を使用し、文字列リストの場合は、テーブル参照を利用
List::MoreUtilsモジュールのany()関数はgrepとほぼ同じだが、
値のどれかが評価ブロックをパスした時点で、trueの値を返して終了する。このため、grepよりも効率的。(パスしない場合は、いずれも値もfalseを返す。)
(でもfirstとanyは何が違う?)
これは、コードブロックに任意の等価評価を作成できるため。
if( any { $fugitive->also_known_as{$_} ) @guests ) {
#略
}
リストのメンバ評価でeqを使用する場合は、参照テーブルを使用するほうがはるかに効果的。
ハッシュアクセスは、配列を線形アクセスするよりも高速である(線形探索を短絡できる場合も含めて)し、コードも読み易い。
Readonly my %IS_EXIT_WORD
= map { $_ => 1 } qw(
q quit bye exit stop done last finish aurevoir
);
if( $IS_EXIT_WORD{$cmd} ) {
abort_run();
}
0 件のコメント:
コメントを投稿