« 高木浩光先生にブクマされたらブクマ数が増えたでござる | メイン | デイリーポータルViewerをバージョンアップ(べつやくれい・林雄司両氏結婚記念ではない) »

2010年3月22日

モダンなPerlを「読む」上で覚えておくとよい構文 第1回(?)

Perl学習者がある程度Perlに慣れてくると、他の人の書いたコードを読む機会も増えてきます。そこでつまづく人は多いのではないでしょうか。かく言う私自身がその一人です(笑)

モダンなPerlはDSL(黒魔術?)的な書き方をしている部分も多く、雰囲気として処理内容をつかみやすいのですが、逆に文法的に構文を理解するのが難しいことも多いです。

「知っている人には当たり前、知らない人には黒魔術」

Perlにはそういうのが多いので、そういったところで悩んでいる人も多いのではないかと思い、このエントリーを書いてみることにしました。気が向けば続きも書きます。間違っている部分もあるかと思うので、ブクマコメ等でご指摘いただけると助かります。

本日の目標とサンプルコード

裸のワード(bareword)は怖くない

encode cp932 => $str;
sub PI(){3.1415926535}

てことで本題に入ります。

=>(ファットコンマ)は要は単なる","(カンマ)である

サブルーチンの括弧は大概省略出来る

Perlに少し慣れてきたかな、くらいの方は以下のようなコードを見るとぎょっとするかもしれません。

print encode cp932 => $str;

「あれ?"=>"ってハッシュを組み立てるときに使う記号じゃなかったの?でもこれってハッシュじゃないよね...?
「cp932って何?そんなキーワード(予約語)知らないけど...?」

実は"=>"(ファットコンマ)ってのはPerlの文法上、働きは単なるカンマと一緒です。

ハッシュを組み立てるときに使われているのは、ファットコンマにしかない

「ファットコンマの直前に置かれた文字列はクオートしなくても良い」

という特徴があり、またペアであることも示しやすいので使われているだけという話なのです。(ただしクオートを省略できるのは、半角英字・アンダーバーから始まり、半角英数字・アンダーバーのみが続く場合のみ。変数命名と同じ)

つまり、以下の2行は同じ意味になります。

my %hash = ( hoge => 'fuga');
my %hash = ('hoge', 'fuga');

また、既に定義が読み込まれているサブルーチンの括弧が省略出来るのは皆さんご存知かと思います。Perlの場合、コード中に予約語ではない裸のワードがあれば、それはサブルーチン呼び出しであることが明らかなので、最近は可読性を損なわない限り括弧なしで書かれることが多くなってきています。同様に、サブルーチンに&(アンパサンド)をつけるのも最近は推奨されていません。

それらを踏まえて最初のコードを初心者に分かりやすい形に書き直すと、以下のようになります。

print encode( 'cp932', $str );

これなら意味は分かるかと思います。Perl文字列をcp932でエンコードして出力しようとしているのです。

cp932について

WindowsではShift_JISを拡張したcp932という文字コードが使われています。Encode.pmでの文字コード指定文字列の'shiftjis'(sjis)と'cp932'はそれぞれ(微妙に)違います。多くの場合cp932を指定しておくと間違いはありません。

また、'utf8'と'utf-8'も違います。脱線しすぎるので説明は省きます。

カンマが使われている箇所はすべてファットコンマで置き換えることが可能ですが、もちろん濫用するものではありません。使いどころとしては、

  • ファットコンマの左側に来る文字列が、単なる文字列以上の意味合いを持つ(何らかのキーワードであるとか)
  • 変数(文字列)が無名関数に渡っているように見せる

といった時に使われています。

ファットコンマの直前の文字列をクオートしない場合の注意点

use utf8;している時に、ファットコンマの前に裸の文字列を置くと、その文字列にutf8フラグが立ってしまうというバグがあります。Perl5.10.2で修正予定らしいです。

ハッシュのキーのクォーテーションは省略出来る

これは個人的には最近まで気持ち悪かったのですが、やっている人が多いので開き直って書き始めました。使ってみると確かに余計な記号が減るのでコードの可読性も上がる気がします。

ハッシュキー指定に裸のワードを使う上での注意点

レアケースですが、同名の定数とバッティングしてしまう可能性があります。その場合は文字列をクオートする、または定数を括弧付きで呼び出す等すればコードの可読性が上がるでしょう。(そもそもそのようなことが起こらないように命名に気をつけるべきですが)

use constant CONST => 4;
my %hash;
$hash{'CONST'} = 5;
$hash{4} = 4;
print $hash{CONST}; # どっち? 正解は5
print $hash{'CONST'}; # 5 
print $hash{CONST()}; # 4

Perlの定数ってのは単なるサブルーチンである

前項目の最後にさりげなく(?)触れましたが、Perlの定数ってのは実は単に引数をとらない関数です。下記2行は(ほとんど)同じ意味です。

use constant PI => 3.1415926535;
sub PI(){3.1415926535}

上の書き方が正当ですが、少しでもコードの実行速度を上げたい場合、constant.pmを呼び出すことのオーバーヘッドを嫌って、下のように定数を定義するコードが書かれていることもよく見かけます。(各種プラグマも結局のところ単なるPerl Moduleです)

PIの後の括弧はサブルーチンプロトタイプ宣言です。PIが引数をとらないサブルーチンだということを明示的にあらわしています。

プロトタイプについて

プロトタイプはあまり使われませんが、

  • サブルーチンを定数として使うとき
  • コードブロックをサブルーチンに渡すとき

なんかに使われるみたいです。つまり黒魔術っぽい書き方をしたいときに使うということです(笑)

ちなみに、引数をとらないことをプロトタイプで明示している場合、多くの場合、コンパイル時にそのサブルーチンの中身がインライン展開されます。つまり高速です。該当箇所にサブルーチンの中身がベタっと貼り付けられるイメージです。

まとめ

今回説明した記述方法の共通点として

「裸のワード」がコード上に増える

ということがあります。

長らく裸のワード(bareword)を嫌ってきたPerlですが、近年は「裸のワードをうまく使う」という傾向が見られるようになってきたと思います。自然な英語っぽく見えて、余計な記号も少ない方が分かりやすい。Rubyなんかの影響もあるのかも知れません。

次回は、無名関数について書こうと思います。

投稿者 Songmu : 2010年3月22日 00:35