Rustのrotate shift

超小ネタ。Rustには標準でrotate shiftが用意されている。例えば左に1つずらすrotate_leftだと、調べてみると基本的な型にはそれぞれ実装されている。ちなみに専用のtraitがあるというわけではないらしい。

doc.rust-lang.org

挙動に関しては特に驚くようなことはない。もちろん、これとは別に<<演算子が用意されていて、挙動が異なるとアナウンスされている。

Please note this isn't the same operation as the << shifting operator!

    let o = 0b11110000u8;
    assert_eq!(o.rotate_left(3), 0b10000111);
    assert_eq!(o << 3, 0b10000000);

ここまではいいのだが、試しにsignedな数値に同じことをしようとしたら、怒られた。

fn test_rotate_shift() {
    let p = 0b10000000i8;
    assert_eq!(p.rotate_right(1), 0b01000000);
    assert_eq!(p >> 1, 0b11000000);
}
error: literal out of range for i8
   --> src/main.rs:158:13
    |
158 |     let p = 0b11110000i8;
    |             ^^^^^^^^^^^^ help: consider using `u8` instead: `0b11110000u8`
    |
    = note: `#[deny(overflowing_literals)]` on by default
    = note: the literal `0b11110000i8` (decimal `240`) does not fit into the type `i8` and will become `-16i8`

どうやら、overflowing_literals属性というのをつけないといけないらしい。

#[allow(overflowing_literals)]
fn test_rotate_shift() {
    let p = 0b10000000i8;
    assert_eq!(p.rotate_right(1), 0b01000000);
    assert_eq!(p >> 1, 0b11000000);
}

これで無事に、signedな数値を、マイナスの符号がついていても2進リテラル表記できるようになった(符号がプラスならば属性がなくとも表記可能)。当然の話だが、rotateの結果は符号を保存しないがshift演算子は符号を保存することにご注意。