&&とandと||とor

&&と||で三項演算を使う

なんだか酒と泪と男と女を思い出してしまうタイトルをつけたわけですが、
返り値が0か1かを返す処理を書く場合に&&と||は重宝します。

私はよく三項演算子をセットにして使います。

三項演算子は書かなくても良いかもしれませんが、後でソースコードを見るとわけがわからなくなるので書いたほうがいいと思います。

スクリプト
#!/usr/bin/perl
use strict;
use warnings;
use utf8;

my $boolean;
warn $boolean = false() && true() && true() ? 1 : 0;
warn $boolean = false() || true() || false() ? 1 : 0;

sub true {
    warn "this is true";
    return 1;
}

sub false {
    warn "this is false";
    return 0;
}
実行結果
this is false at script/op.pl line 19.
0 at script/op.pl line 7.
this is false at script/op.pl line 19.
this is true at script/op.pl line 14.
1 at script/op.pl line 8.
解説

A && B && C は、A, B, Cの全てが1の場合に真となります。ということはAの結果が偽だった場合はBとCの処理は行いません。

A or B or C は 真の結果が得られるまで順番にA, B, Cと処理をしますが、真が得られた場合は残りの処理をスキップします。

and と or

and と orはそれぞれ&&と||と同じ挙動をします。が、しかし次のスクリプトをご覧ください。

スクリプト
#!/usr/bin/perl
use strict;
use warnings;
use utf8;

my $boolean;
warn $boolean = false() and true() and true() ? 1 : 0;
warn $boolean = false() or true() or false() ? 1 : 0;

sub true {
    warn "this is true";
    return 1;
}

sub false {
    warn "this is false";
    return 0;
}
実行結果
:!perl script/op.pl
this is false at script/op.pl line 19.
0 at script/op.pl line 10.
this is true at script/op.pl line 14.
this is true at script/op.pl line 14.
this is false at script/op.pl line 19.
0 at script/op.pl line 11.

あれあれあれ、、、なんかちがうよ。

解説

演算子の優先順位が違うらしい。

12:23 (kan)     ||だといけるのにorだと駄目なのは、三項演算子との優先順位の問題だと思います>おかむらさん
12:24 (okamura) なんと

perldocjpみてみる

perldocjp -J perlop
左結合      &&
左結合      || //
……
右結合      ?:
……
左結合      and
左結合      or xor

おおー挙動が同じだけど演算の優先順位が違うのねー

なのでA and B and C ? 1 : 0の場合は次の処理をしています*1

  • A ? 1 : 0
  • そして0を返したのになぜか Bが評価されている
  • Bが真を返したのでCも評価される。
  • Cは1を返しているけど既にA ? 1 : 0によって左辺の変数には0が格納されている

とりあえずA and B and C ? 1 : 0みたいな処理書いちゃだめでA && B && C ? 1 : 0と書くようにしよう*2

翌日追記

というわけで翌日社内にて「()で囲めばいいんじゃない?」と言われ、己の未熟さを思い知らされるわけです。

ソウデシタネ。ソウスレバイイデスヨネ。

で、「A or B or C ? 1 : 0」は最初にC ? 1: 0が演算されているいのでは?という疑問も頂戴したので次のようなコードを用意しました。

#!/usr/bin/perl
use strict;
use warnings;
use utf8;

my $boolean;

warn $boolean = A() and B() and C() ? 1 : 0;
warn "-" x 10;
warn $boolean = a() and b() and c() ? 1 : 0;

warn "-" x 10;

warn $boolean = A() or B() or C() ? 1 : 0;
warn "-" x 10;
warn $boolean = a() or b() or c() ? 1 : 0;

sub A {
    warn "A";
    return 1;
}

sub a {
    warn "a";
    return 0;
}

sub B {
    warn "B";
    return 1;
}

sub b {
    warn "b";
    return 0;
}

sub C {
    warn "C";
    return 1;
}

sub c {
    warn "c";
    return 0;
}

結果

:!perl script/op.pl
A at script/op.pl line 19.
1 at script/op.pl line 8.
B at script/op.pl line 29.
C at script/op.pl line 39.
---------- at script/op.pl line 9.
a at script/op.pl line 24.
0 at script/op.pl line 10.
b at script/op.pl line 34.
---------- at script/op.pl line 12.
A at script/op.pl line 19.
1 at script/op.pl line 14.
---------- at script/op.pl line 15.
a at script/op.pl line 24.
0 at script/op.pl line 16.

ま、とにかくなんでそうなるかはもういいや。今は()をつけて書く、そうしよう。

*1:たぶん

*2:いや、それが意図した処理なら構いませんが…