perlでは何がtrueで何がfalseと判定されるのか

perlでMySQLをいじっていた時に自分の予想と反する動きをして混乱したので、この機会にperlのtrue/falseについてまとめていく。

perlでは何がtrue/falseと判定されるのか?

公式ドキュメントに書かれている様に、perlでは以下の5つがfalseと判定されて、他はtrueと判定される。

  • 数値 0
  • 空文字列 ''
  • 0の文字列 '0'
  • 空リスト ()
  • undef

数値 0, 文字列 '0' と "", 空リスト (), undef は全て真偽値 コンテキストでは偽となります。 その他の全ての値は真です。 真の値を ! や not で否定すると、特殊な偽の値を返します。 これを文字列として評価すると "" として扱われますが、数値として評価すると 0 として扱われます。 真または偽を返す、ほとんど Perl の演算子はこのように振る舞います。

perlsyn - Perl の文法 - perldoc.jp

実際に以下のコードを実行すると、予想通りの結果が出てきた。

print("'' is false\n")   unless '';
print("0 is false\n")    unless 0;
print("3 is false\n")    unless 3;
print("'0' is false\n")  unless '0';
print("name is false\n") unless $name;

= result
'' is false
0 is false
'0' is false
name is false

配列やハッシュの真偽値

データベースなどをいじっていると、「空のハッシュが返された時に、エラー文を表示させたい」と考えることがよくある。この様な場合は、単に配列やhashをif文の中に入れてあげれば良い。

例えば、以下の様な感じで。

my %hash = ();

unless (%hash) {
    print "false\n";
}

= result
false

しかし、実際にハッシュを扱う時は、リファレンスとして扱う場合が多いと思う。もし、hashリファレンスの真偽値を求めたい場合は、デリファレンス%$hashをしてあげれば良い。

my $hash = {
    username => 'toumasu',
    age      => 15,
};

if (%$hash) {
    print "true\n";
}

my $empty_hash = {};

unless (%$empty_hash) {
    print "false\n";
}

=result
true
false

組み込み関数definedを使っての真偽判定

perlの組み込み関数(公式が用意してくれている関数)としてdefinedが用意されている。このdefinedとは、値が定義されている(undefではない)場合はtrueを返してくれる関数だ。

my $str = 'sample';

print "defined" if defined $str;

=result
defined

もちろん、definedを使わなくてもundefかどうかの判定はできるが、単にif($str)の様に条件文を書くと、$str変数がundefなのか0なのか空文字なのかの区別が付かない。

なので、undefの時に例外エラーを出したいという時にdefinedを使うことで、期待通りの動作をしてくれる様になる。

ここで気をつけたいのは、あくまでdefinedが評価するのは変数が未定義undefかどうかのみなので、空の配列やハッシュ、文字列はtrueと判定される、ということだ。(たとえ空でも定義されているからtrueになる。数値の0もtrueの判定になる)

また、define(%hash)の様に配列やハッシュで判定しようとすると、「非推奨だよ」というエラーが返ってくる。

defined(%hash) is deprecated at main.pl line 3.
        (Maybe you should just omit the defined()?)

集合(ハッシュや配列)への defined の使用は もはや対応していません。 これはその集合にメモリが割り当てられたかを報告するのに用いられていました。 代わりにサイズに対する簡単なテストを使うべきです。

if (@an_array) { print "has array elements\n" }

>if (%a_hash)   { print "has hash members\n"   }

ハッシュの要素に対して用いると、value が定義されているか否かを 返すものであって、ハッシュに key が存在するか否かを返すのではありません。 この用途には、exists を使ってください。

Perlの組み込み関数 defined の翻訳 - perldoc.jp