Perl Hackers Hub

第7回新人さんのための仕事で使えるPerl基礎知識(2)

変数

Perlには混乱を招きやすい表現が多々あり、最初はとっつきにくい印象を受けるかもしれません。TMTOWTDIと呼ばれる「There's more than one way to do it」⁠やり方は一つじゃない)というPerlの思想のとおり、実現するためにはいくつもの表現方法があります。

(2)ではPerlの変数やスコープ、特殊変数や例外処理など、Perlを理解するために筆者が最初に時間がかかった個所について重点的に説明をします。

use strictとuse warnings

「Perlはコードがわかりにくくなる」といった意見をよく聞きますが、strictとwarningsのプラグマを使うことによって、ぐっとコードが読みやすくなるうえ、メンテナンス性が格段に向上します。

use strict

ワンライナー以外のプログラムに関してはusestrict;宣言をすることが推奨されています。これは、変数宣言が確実に行われているかどうかを確認するためのものです。

use strict;
$var = 1; # エラー

use warnings

新規でコードを書く際にはuse warnings;宣言をすることが推奨されています。これにより、バグになる可能性の高いコードがあれば自動的に警告してくれます。実行する際に変数の中身がundefのままになっているような場合であっても警告してくれます。

小飼弾さんのperl - use warnings; # -w でなくてという記事にて、具体的な例とともにわかりやすく説明されています。

スコープ制御

スコープとは、変数アクセス(参照)できる範囲のことです。

レキシカルスコープ宣言とグローバル宣言

Perlでは、myで宣言されたスコープをレキシカルスコープ宣言と呼びます。宣言が行われた場所から囲んでいる内側のスコープの最後までが有効範囲です。localやourで宣言することをグローバル宣言と呼びます。

my

my宣言した変数は、純粋にスコープの中でのみ有効なレキシカル変数です。スコープ外からはアクセスできません。

{
    my $var = 1;
}
print $var; # エラー

local

local宣言した変数は、同名のグローバル変数(サブルーチンやフォーマット宣言された変数)の値を、スコープ内にいる間だけ一時的に書き換えます。スコープの範囲を外れると一時的な値は捨てられて元の値に戻ります。実行している途中で値が変わることからダイナミックスコープ(動的スコープ)と呼ばれます。

my %h = ( var => 'foo' );
{
    local $h{var} = 'ok';
    print $h{var}; # ok
}
print $h{var}; # foo

our

our宣言した変数はグローバル変数としてプログラム全体に対して定義され、プログラムのどこからでもアクセスできます。ourはuse varsと等価だと考えられており、次のように定義できます。

package SampleApp;
use strict;
use warnings;
our $VARIABLE = 1;

別の場所からグローバル変数にアクセスする際には、$名前空間::変数名でアクセスします。省略した際にはデフォルトでmainというパッケージ名(名前空間)になります。

package SampleApp2;
$SampleApp::VARIABLE;

よく使われる特殊変数

Perlには、特殊変数と呼ばれる特別な意味を持った変数が用意されています。使用頻度の高い特殊変数から順に覚えて使用することで、プログラミングがより便利になります。

ここではよく使われる特殊変数を紹介します。

$_

$_は非常によく使われる特殊変数です。デフォルト変数とも呼ばれ、デフォルトで値が入っているであろう期待値として作用するようになっています。

次の例では、@arrayという配列をforeachでループさせ、ループ内にprintで特殊変数の$_を表示させています。

my @array = ('cat', 'dog');
foreach ( @array ){
    print 'array is: ' . $_ . "\n";
}

上記のコードは配列の中の要素を1つずつ取り出したものをデフォルトとして、自動的に代入と出力を行います。実行結果は次のようになります。

array is: cat
array is: dog

@_

@_は、サブルーチンを作る際に引数を受け取る配列変数です。引数で渡された変数がすべて1つの配列にまとめられてサブルーチンの@_変数から引数を取ることができます。@_から受け取りの際に一度代入することは、サブルーチンに引数として渡した参照データを直接書き換えたり壊さないようにするためです。

sub foo {
    my($x, $y) = @_;
    print "$x, $y\n";
}
foo(1, 2);

実行結果は次のようになります。

1, 2

$@

$@は、例外エラーをevalでキャッチしたときのメッセージです。Javaのtry/catchとほぼ同等の機能を、Perlではdie/evalと$@を使うことで実現します。Perl組み込み関数のdieがJavaなどのthrowに該当しており、dieを受け取りたい部分のコードをevalブロックでくくることによって例外処理します。

evalには主に2種類の用途があります。

1つめは、evalの引数に文字列を渡すことによって、動的に実行されるコードを変更したいようなときに使います。渡された文字列全体をPerlのコードであるとみなして実行中にコンパイルを行います。

my $code;
for my $name ('foo', 'bar') {
    $code .= qq/sub $name { print "this is $name\n" }/;
}
eval $code; # fooとbar
foo(); # tis is foo
bar(); # this is bar

2つめは、evalの引数としてブロックを渡して、ブロックの中で発生した例外エラーの捕捉を行うときに使います。エラーだった場合は$@にエラーメッセージを格納します。evalを使うことによって、Perlの異常終了をハンドリングできます。

eval{
    die 'エラーです'; # 例外が発生
};

if( $@ ){
    print "Error: $@\n"; # $@にエラーメッセージが入る
}

なお、Try::Tinyというモジュールを使うことにより、ほかの言語のようにtry {} catch {}構文を使って例外処理を書くことができます。

use Try::Tiny;

try {
    die 'クリティカルなエラーです';
} catch {
    warn "エラーです: $_";
}

擬似シグナル

Perlでは、__WARN____DIE__といった疑似シグナルもサポートしています。ここにコードを指定すると、warnが呼び出された際の挙動を変えることができます。

次のコードを実行すると、warnはdie 'foo'と同様の挙動になります。

local $SIG{__WARN__} = sub { die $_[0] };
warn 'foo';

おすすめ記事

記事・ニュース一覧