Rust で [u8; n] から数値を復元する

ビットシフトでもだいじょうぶ

最近 Rapberry Pi などからセンサー類を起動して遊ぶということをしています。

そういうモジュール類から得られるデータは基本的に単なる u8 の配列です。したがって、指定された型に戻す必要があります。

指定された型が u8 を超える範囲の数値の場合、ビットシフトを使って復元します。

let received: [u8; 2] = [0xf2, 0xf4];
println!("{}", (received[0] as u16) << 8 | received[1] as u16);
// => 62196

ビットシフト自体は話が簡単なのですが、もとが u8 なので Rust ではオーバーフローが指摘され、キャスティングなしにコンパイルができません。

println!("{}", received[0] << 8 | received[1]);
// 6 |     println!("{}", received[0] << 8 | received[1]);
//   |                    ^^^^^^^^^^^^^^^^ attempt to shift left with overflow

型キャスティングが必要になると演算子の優先順位から () も必要となり、コードのみためが多少煩雑になります。

from_be_bytes

そこでその煩雑さから逃れつつ、簡単に狙ったバイト長の数値に変換するための from_be_bytes というメソッドが数値型に用意されています。

let received: [u8; 2] = [0xf2, 0xf4];

println!("{}", u16::from_be_bytes(received));
// => 62196

println!("{}", i16::from_be_bytes(received));
// => -3340

これで演算子の優先順位に悩まされることなく、安全に望む数値を手に入れることができます。

余談

実際の処理では 3 bytes 中の真ん中のバイトの上下 4 ビットが 1 バイト目と 3 バイト目の下位ビットにあたるようなことがあり、ビットシフト自体からは離れられないようです。