Perl日記

PerlとかRubyとかPHPとかPythonとか

looks_like_number()の返り値とエクスクラメーションによるBoolean反転

昨日のlooks_like_number()の返り値がよくわからなかったので、cpanからinstallするときのtestを落として見てみた。

$ cpan
cpan[1]> get Scalar::Util
$ cd ~/.cpan/build/Scalar-List-Utils-1.23-npHgm2/t/
$ grep looks_like_number ./*
./lln.t:use Scalar::Util qw(looks_like_number);
./lln.t:  ok(looks_like_number($num), "'$num'");
./lln.t:is(!!looks_like_number("Inf"),      $] >= 5.006001,     'Inf');
./lln.t:is(!!looks_like_number("Infinity"), $] >= 5.008,        'Infinity');
./lln.t:is(!!looks_like_number("NaN"),      $] >= 5.008,        'NaN');
./lln.t:is(!!looks_like_number("foo"),      '',                 'foo');
./lln.t:is(!!looks_like_number(undef),      '',                 'undef');
./lln.t:is(!!looks_like_number({}),         '',                 'HASH Ref');
./lln.t:is(!!looks_like_number([]),         '',                 'ARRAY Ref');
./lln.t:is(!!looks_like_number($bi),        1,                  'Math::BigInt');
./lln.t:is(!!looks_like_number("$bi"),      1,                  'Stringified Math::BigInt');
./lln.t:is(!!looks_like_number($foo{'abc'}),        '',                 'Tied');
./lln.t:is(!!looks_like_number($foo{'123'}),        1,                  'Tied');
./lln.t:is(!!looks_like_number("\x{1815}"),        '',                  'MONGOLIAN DIGIT FIVE');

出た。


「!!」なんだこれは!!。


Perlにおけるエクスクラメーションマーク!って、Boolean反転っていうのは知ってたけど、えと、なんで二個連続で重ねてんの?
そういえば今までエクスクラメーションマーク!をifとかの条件分岐でした使ったことなかったから、何が返されてるのかは知らなかったっけ。


というわけで先に「エクスクラメーションマーク!」について調べる。

「!」一個

文字列の場合
say !'Hello';

何も出ない。

空文字列の場合
say !'';
1

1が出た。

数値[^0]の場合
say !198765;
say !-1;

やっぱり何もでない。

数値[0]の場合
say !0;
1

1が出た。

undefの場合
say !undef;
1

1が出た。

リファンレスの場合
my $a_ref = [];
say !$a_ref;

出ない。


出ないときの中身は空文字列かundefのどちらだろうか。

my $what = !1;
say defined $what ? 'karamojiretsu' : 'undef';
karamojiretsu

空文字列でした。

ということは

あーなるほど。
だから上のテストはこうなっているのか。

is(!!looks_like_number($bi), 1, 'Math::BigInt');

一個目の「!」で空文字列になって、二個目の「!」で「1」になる、と。
つまりこれは前回のエントリ最後の、looks_like_number()は、1か0を返しているわけではないということを裏打ちしているわけだ。
1以上の正の値であることは保証しているけれど、それが何になるかは環境に依存するという感じかな(推測です)。


もう一つ。

is(!!looks_like_number(undef), '', 'undef');

一個目の「!」で「1」になって、二個目の「!」で空文字列になって、それがis()で比較されると。
でもなんでこれだとだめなんかな。

is(looks_like_number(undef), 0, 'undef');

こっちも何か保証されていないfalseが返ってくることがあるのだろうか。


参考:
[Perl][PHP]値がfalse ならtrue に、true ならfalse にするtoggle(ビット反転)はこう書ける | ブログが続かないわけ