Perl5.10以降に追加された機能で良く使うお役立ち機能まとめ
Songmuです。
Perlは5.10以降多くの機能が追加されていますが、巷のCPANモジュールの多くは5.8と互換性を保って書かれていることもあり、普段その機能を目にしない人も多いでしょう。僕自身のCPANモジュールも多くは5.8.1以降対応ですが、最近手元で動かすようなものに関しては5.10.1対応にすることも増えてきましたがそれでも、5.10.1止まりです。
実際のプロジェクトにおいては5.10以降の機能も使えるものは積極的に使っているのでその辺りの話。
say
: 改行付きprint (5.10)
print
してその後に改行を入れてくれる関数です。地味に便利です。
use 5.010;
say 'Hello'; # Hello
ワンライナーでも -E スイッチで使えるようになるので近年は-eを使わずに専ら-Eです。
% perl -E 'say "Hello"'
Hello
//
: defined-or (5.10)
初期化されていない変数に初期値を代入するために以下のようなコードを書く事があるでしょう。
my $hoge = $fuga || 10;
$piyo ||= 15;
||
で真偽判定をしているわけですが、この場合、$fuga
や$piyo
に0が入っていた場合に意図しない挙動になってしまうかも知れません。Perlはundef
の他に、空文字列や0も偽値として扱います。ただ、上記のような場合、厳密にundefかどうかを判定したいときもあります。そういう時に//
を使います。
my $undef;
my $zero = 0;
my $hoge = $zero || 10; # $hoge == 10
my $fuga = $zero // 10; # $fuga == 0
my $piyo = $undef // 10; # $piyo == 10
初期化されてない変数に初期値を入れるみたいな処理を書くときに重宝します。
$hoge //= 10; # undefだったら10を代入する。0の場合は0のまま
これは5.8以前だと、$hoge = defined $hoge ? $hoge : 10;
などと書かないといけませんでした。
ところで、空文字や0が偽値になるっていうのは好き嫌いはあるかと思いますが僕は好きです。
state $var
: Persistent Private Variables (5.10)
永続的なレキシカル変数です。同じスコープに入っても再度初期化処理がされないというのがmy
と異なります。
毎回同じ値を使うのに、同じ初期化処理が走るのは無駄に感じるときとかに使います。Data::ValidatorのSYNOPSISでも使われています。
例えば以下はFurlで指定したURLの内容を取得する処理ですが、この関数が2回目以降に呼ばれた場合は$ua
は再度初期化はされずに、同じオブジェクトが使いまわされることになります。
sub get_url {
my $url = shift;
state $ua = Furl->new;
$ua->get($url);
}
state
では同じ変数が使いまわされることになるので、副作用のある変数を使う時は多くの場合オススメできません。メモリキャッシュ的な用途での使い途はありますが、注意が必要です。
-f -x $file
: ファイル演算子が重ねられる (5.10)
ファイル演算子が重ねられます。具体的には、ファイルであり実行可能であるみたいな条件を以前は
-f $entry && -x $entry
などと書いていたところを
-f -x $entry
と書けます。地味に便利。
~~
: smart match (5.10)
よしなマッチ。5.18から実験的機能に格下げになってしまったので、あまり積極的に使わない方が良いでしょう。僕は配列内の存在チェックとかで地味に便利なのでそこだけは使っています。
$var ~~ [1,2,5,8,10];
スマートマッチを使わない場合だと以下のように書かないといけないのが地味に面倒です。
grep {$var == $_} 1,2,5,8,10
given ... when
: switch (5.10)
switch文的なやつ。Rubyのcase式みたいによしなマッチ的なこともしてくれます。と言うか内部的に前項のsmart matchを使ってるからなのです。なので、smart matchが実験的な機能になってしまっているので、given ... when
も実験的な機能に格下げされています。悲しいですね。
ちなみに、switchを実現するSwitch.pmというモジュールがあるのですが、これは絶対に使ってはけません。これが一番言いたかったことです。理由はググってください。
...
: yada-yada operator (5.12)
未実装の部分を...
として宣言することができます。実行時にそこを通った時に例外を吐いてくれます。
% perl -E 'sub { ... }->()'
Unimplemented at -e line 1.
あまり使うことはないのですが、...
という文字列がサンプルコードとしてvalidであったりするのがちょっと便利。もしくはモジュールなんかでも「このメソッドは将来的には用意するつもりだよ」的なことを示すのに使ったりできます。
use 5.012;
: 暗黙的なuse strict (5.12)
5.12以降は、use 5.012
, use 5.018
などとすると、そのバージョンのfeatureが使えるほか、自動的にuse strict
扱いしてくれるようになっています。地味に便利。
s///r
: 非破壊的な正規表現置換 (5.14)
s///
による置換は破壊的なので、元の文字列に変更を加えたくない場合は別の変数に移し替える必要がありましたが、/r
修飾子を使うことで非破壊的になり、置換結果を左辺に返してくれるようになりました。
my $str = 'moznion';
my $str_result = $str;
$str_result =~ s/moz/hage/; # hagenion
が以下のように書けます。
my $str = 'moznion';
my $str_result = $str =~ s/moz/hage/r; #hagenion
あんま便利に感じられないかもしれませんが、例えば以下のように配列の全要素に置換をかけてその結果を返すみたいなときに威力を発揮します。
my @replaced = map {s/hoge/fuga/r} @orig;
各要素を置換した結果が@replaced
に入ります。元の文字列は破壊されないため、@orig
に意図しない変更が入ることもありません。
package NAMESPACE {...}
: ブロック付きpackage宣言 (5.14)
package宣言がブロックを伴うことができます。
package Hoge;
...
などと書いていたところを
package Hoge {
...
}
と書くことができるようになりました。1つのファイル内に複数のパッケージ宣言を書きたい時とかにスコープをちゃんと分けられます。もともと
{
package Hoge;
...
}
と書くこともできて、同じことではあるのですが、それがかっちょよく書くことができるようになったということです。
個人的な使い方としてはファイル名と一致するNamespaceのパッケージはブロック付きにはせず、インナーパッケージはブロック付きで宣言するようにしています。以下の様な具合です。
# Foo/Bar.pm
package Foo::Bar;
...
package Foo::Bar::Inner {
...
}
1;
push $arrey_ref, 'hoge';
: オートデリファレンス (5.14);
5.14以降に実験的な機能としてオートデリファレンスが実験的な機能として入っています。
便利だと思うのですがあまり好んで使っている人がいないので、僕も使わないようにしています。
- Perlっぽくない
- いつオートデリファレンスが発動するかわかりづらい
- 意図しない挙動になりそうで怖い
というのが理由でしょうか。実際問題として、for my $elm ($array_ref) {...}
みたいなところでは、オートデリファレンス効かない(効いたら効いたで困ることもある)ので、わかりづらいってのはありそうです。
Perlにはwantarray
というちょっとわかりづらいよしな機能があるので、そういう暗黙的に便利なことをしてくれちゃうみたいなことに対しては慎重な態度を取るってのが最近のPerl界隈の傾向かも知れません。
my sub hoge {...}
: lexical_subs (5.18)
名前付き関数はネームスペースで区切ることはできるもののグローバルですが、レキシカルな関数宣言が5.18以降、できるようになっています。まだ実験的な機能で僕も使っていません。
my $sub = sub {...}
ってやればいいし、別にこの機能いらないんじゃないの?っていう意見が大勢だったのですが、Exporter::Lexicalの登場で、実はこの機能は熱いんじゃないかという感じになってきています。Exporter::AutoClean的なことが簡単に実現できるわけです。
ということで、Perl5.10機能のお役立ち機能をまとめてみました。明日はpapix君でしょうか。2回目ですね。まこぴーとはなんだったのか。
と思ったらまこぴーが書くようです。