人それぞれにコーディングスタイルの好みがありますが、読みやすく、理解しやすく、保守しやすいプログラムにするための一般的なガイドラインはあったほうが良いでしょう。Perlであれば、作者のラリーが発表しているので、それに最近の傾向を反映させたお勧めのスタイルを紹介します。
1.オススメのスタイル
条件式の書き方
if ( 1 ){ $value = '*****'; # タブでインデントしている }
用語
1行文の書き方
- 1 行で済むブロックは1行で書く
- 短い1 行のブロックでは、セミコロンを省く
if ( 1 ){ $flg = 1 }
式の書き方
- 演算子の両端にスペースを入れる
演算子が目立ち、読みやすくなります。
$result2 = $p + 1000 / 2;
- カンマ( , )のあとにはスペースを入れる
- 対応する項目は、カラムを揃えて縦に整列する
%hash = ( A, 1000, B, 1001, C, 1002, D, 1003 );
読みやすい書き方
- 動作内容の異なる処理ごとに空行を入れる
- else は if/unless の閉じ中カッコ( { )と同じ行にする
- 長い行は数行に分ける
1つの文を何行かに分ける場合は、コンマで区切ったリストの後や、演算子の後など、自然に見える場所で改行しましょう。改行した行はインデントを忘れずに。
open( FH, "<$text"); while( <FH> ){ print $_; } close( FH ); if ( $value1 eq 'MEN' ) { print "good by!\n"; } else { print "welcom!\n"; } sub display_msg { ( $value1, $value2 ) = @_; if ( $value1 / 10000000 + 2000000000 > $value2 / 10000000 + 2000000000 ){ return 0; } return 1; }
- 変数の宣言はなるべくサブルーチンの先頭に置く
- 変数の宣言と次の実行処理の間に空行を置く
sub function{ my $a = 10; my $b = 20; my ($word, $cnt); .... }
2.オススメのプログラミング作法
Perlに警告してもらう
常にプログラムを-wフラグを指定して実行しましょう。もし必要なら、$^W変数を使って、プログラムの特定の部分について、警告をオフにすることができます。また、常に
use strictを指定するようにしましょう。
#! /usr/local/bin/perl -w use strict; .....
同じものを改めて作らない
プログラミングの最中に、同じような処理を行う箇所に気づくことがあります。このようなときは、サブルーチンにして切り出すか、モジュール化を考慮する習慣をつけましょう。
コメントは適切に
コメントを適切に書いておくことは重要です。コメントを入れる場所としては、プログラムの先頭、サブルーチンの前、複雑な処理の前がよいでしょう。
ただし、コメント文は多すぎないように気を付けましょう。コメント文がなくても、すぐに処理内容がわかるようなコーディングを心がけるべきです。
読みやすいスタイルを心がける
Perlは自由度が高い言語ですから、同じ処理をするにも様々な書き方があります。どの方法で処理するかは、もっとも読みやすいものを選ぶとよいでしょう。
また、デフォルトの値や省略可能なカッコや記述が様々に用意されていますが、最初はなるべく使わないようにしましょう。プログラム作成時は問題なくても、後で修正するときに処理の内容がわからない、といったことがあります。
ループラベルはお好みで
ループラベルの使用はあまり推奨されていません。ですが、ループラベルが必要な場合は、使ってもかまわないでしょう。多重のループからの脱出するためでもありますが、読みやすくなります。結局のところ、ループラベルを使うか、使わないかは好みの問題です。
正規表現は簡潔に
複雑な正規表現には、x修飾子を使って、スペースを入れるなどして、なるべく見やすくしましょう。正規表現の中にスラッシュやバックスラッシュを使っている時は、区切文字はスラッシュ以外にし、頻繁なエスケープ処理を避けましょう。
# 少し読みにくいですね $value =~ /\/home\/httpd\/html\/*\.html/; # 上記と同様の処理ですが、区切り文字を | にして、エスケープ # 処理を避けています $value =~ m|/home/httpd/html/*\.html/;
アンドは"&&"よりも"and"が自然
論理演算子の && や || といった記号的な演算子よりも、直感的にわかりやすい "and" や "or" を使いましょう。
連続した print 文
連続した print() 文がある場合は、変わりにヒアドキュメントを使いましょう。
# 連続した print 文 print "<html>\n"; print "<body>\n"; print "You might win some but you just lost one\n"; print "</body>\n"; print "</html>\n"; # 上記と同様の処理ですが、ヒアドキュメントを使っています print <<EOF; <html> <body> You might win some but you just lost one </body> <html> EOF
クォートを含む文字列に対しては qq// を使う
クォートを含む文字列をクォートで囲むためには、バックスラッシュ( / )でエスケープする必要があります。このような場合は、q//、qq//、qx//を代わりに使うようにしましょう。
# 同様の処理ですが、qq//を使ったほうが見た目がいいですね $word = "Look at your career they said,\"Baby use your head\""; $word = qq{Look at your career they said,"Baby use your head"};
浮動小数点を信頼しない
ほとんどのコンピュータでは、浮動小数点は近似値になります。たとえば、10を3で割ると「3.3333...」と無限に続きますが、コンピュータは値を保存する領域に制限があるので、途中で3の繰り返しをストップさせます。
末桁まで正確であることを前提にしてプログラミングを行うと、致命的な問題に直面します。金額などを扱う場合などは、特に注意しましょう。
セキュリティの問題
システムコールとバッククォーテーション操作の戻り値は、なるべくチェックするようにしましょう。
移植性を高める秘訣
移植性のため、すべてのマシンで利用できない機能を使う場合には、eval の中で使ったほうが安全です。
再利用性を高める秘訣
再利用性を考えましょう。何も考えずに作成するほうが簡単ですが、あとで簡単に再利用できるように作成しておいたほうが、長い目で見て作業が楽になります。
3.処理スピードを速くする!
- 条件式では、式を終わらせる可能性の高い条件を左端に置く
and 演算子を使う式などでは、最も偽りになる可能性のある条件を左端に置くようにします。or
演算子を使う式では、最も真になりそうな条件を左端におきます。 - goto文を使わない
- print文で十分なら、prinf は使わない
printf は、実装によってフィールド長に制限があります。 - $& 、$' を使わない。
これらの変数をプログラム中で1回でも使っていると、パターンマッチの結果が保存されるようになります。1回でも使ってしまえば、あとは何回使っても同じです。 - ループの中で eval を使わない
eval
は特殊変数全てを初期化したり、再コンパイルを行うので、処理に時間がかかります。どうしてもループの中で
eval を使いたい場合は、ループ自体を eval の引数にしましょう。 - 引数が文字列の eval を使わない
ブロックが引数の eval
はコンパイルを一度だけを行いますが、文字列が引数の場合は、使用されるたびに再コンパイルされます。 - next if を利用する
ループ文の中で「・・・の場合は処理を飛ばす」というケースが考えられるときは、ループの最初に next
if で処理します。 - ループの中でサブルーチンを呼び出さない
サブルーチンの頻繁な呼び出しは処理を遅くさせます。特に、複数のパラメータを渡すサブルーチン呼び出しは避けましょう。 - 連続した substr の使用をなるべく避ける
substr を繰り返す代わりに、 pack や unpack で済ますことができます。 - $foo = $a || $b || $c を使う
次のように書くよりずっと速く処理されます。
while ( <FH> ){
# 行の先頭に数字以外の文字がある場合は処理を飛ばす
next if /^\D/;
...
}
if ( $a ){ $value = $a; } elsif ( $b ){ $value = $b; } elsif ( $c ){ $value = $c; }
- tr の方が s///g よりも速い
- foreachや配列演算子でできることには、インデックス付けを使わない
インデックス付けを行うと、浮動小数点の演算と浮動小数点から整数への変換が必要になります。 - システムコールを避ける
オペレーティングシステムに対するシステムコールはボトルネックになる可能性が高いです。 - system を使わない
system
はサブプロセスをフォークしてからプログラムを実行します。さらに、シェルを実行する場合もあります。
4.空間の効率を上げる!
- vec を使えば整数の配列をコンパクトに表現することができる。
- 文字列よりも数値を使うこと。
- substr を用いて、固定長の文字列を長い文字列の中に格納する。
- __END__ と <DATA>
ファイルハンドルを活用して、データを文字列と配列で重複して保持するのを避ける。 - 順番がランダムでよければ keys ではなく each を使うようにする。
- 使わなくなったグローバル変数は削除するか undef する。