Reference を眺めていたら論理演算子についての興味深い記述に気づいたのでメモがてら紹介します.
本論
次のコードを実行するとどうなるでしょう? PlayGround
fn main() {
let x = true || panic!();
println!("{}", x);
}
Or 演算子の評価は lazy で, 左側に true が来ている時点で右側の値によらず true || panic!() の戻り値は true になります. 従ってこのコードは右側の値を評価しないため, パニックせず true を出力します.
And 演算子も同じです.
fn main() {
let x = false && panic!();
println!("{}", x);
}
応用
この性質を利用すると, 次のコードでは重たい計算 very_expensive_calculation は必要がなければ処理が省略されます.
if condition && very_expensive_calculation() {
// 省略 //
}
もちろん if 文をネストすれば同じことができますが, いろいろと活用できそうです.
注意
ビット演算 BitOr および BitAnd は当然ながらこの性質を持ちません. ただビット演算子の左側に bool, 右側に panic!() があると, panic!() が bool を返さない (() を返す) ためにコンパイルエラーになります. よくできてますね…
若干話は変わりますが, Rust の true, false のバイナリ表現はそれぞれ 1u8, 0u8 であることが定められているのかどうか, という疑問が湧いたので, ついでに調べました. Reference の Boolean Type には 1 byte ですよ, とのみ書かれていますが, Behavior considered undefined の部分に
A value other than
false(0) ortrue(1) in a bool.
が挙がっていたので, それで間違いなさそうです1. ちなみに as で整数にキャストした場合の振る舞いは std の方に記述があります.