ごらくらいふ

プログラミングしたりゲームしたり

Rust Vec<T>を特定の長さで分割する

背景

gifとかzipとかパースしたいなあ+Rust触りたいなあ! ということで、まずはバイナリダンプから始めようとした。

以下のようなフォーマットで標準出力に吐き出したい。

50 4b 03 04 00 00 00 00 00 00 00 00 00 00 00 00 | PK.............. 

一行出力するにあたり、バイナリのほか、一時的に格納した文字列情報が必要。

最初はfor文に食わせて、愚直にカウンタ制御でVecに文字を詰めたり改行して実装した。 当然ながら、どこまで出力されているかを意識してコードを書かなければならない。

これではしんどいので、octet単位ではなく行単位の出力で考えたい。

目的

Vec<u8> *1 を二次元配列的に扱えるように変換する。

結論

let lines: Vec<&[u8]> = binary.chunks(BYTES_IN_LINE).collect();

各行の長さをあとで変えたり、所有権も持たせたくてVec<Vec<u8>>が良いならば以下のとおり。

const BYTES_IN_LINE: usize = 16;
let lines: Vec<Vec<u8>> = binary.chunks(BYTES_IN_LINE).map(|chunk| chunk.to_vec()).collect();

余談

.chunksを探しに行く前に、愚直に作る処理を書いてみたのだけれど、これが数行で済むのだから便利だなぁ。

const BYTES_IN_LINE: usize = 16;
let lines: &mut Vec<Vec<u8>> = &mut vec![];
let mut line: Vec<u8> = vec![];
for octet in binary {
    line.push(octet.clone());
    if line.len() >= BYTES_IN_LINE {
        lines.push(line);
        line = vec![];
    }
}
if line.len() > 0 {
    lines.push(line);
}

*1:軽量なデータから始めるので、fs.read(path) -> Vecを使う。