【Rust】as_bytes()でcannot borrow as mutable(E0596)エラー

Posted on
Rust trouble-shooting

cannot borrow data in a `&` reference as mutable

共通鍵関連で、DES暗号化をRustで実装しているんですが、そのときにちょっとハマりかけたのでメモ。

fn main() {
    let mut src = "abc".to_string();
    let mut s = src.as_bytes();

    println!("{:08b}", &s[0]);
    set_bit(&mut s, 0);
    println!("↓");
    println!("{:08b}", &s[0]);
}

fn set_bit(bytes: &mut [u8], bit: usize) {
    bytes[bit / 8 as usize] |= 0x80 >> (bit % 8);
}
Code 1: 問題となったコード

処理自体は単純で、文字列をbyte配列に変換後、指定されたビットを立てるような感じです。

ただ、このソースをコンパイルしようとすると、下記のようなエラーが発生します。

error[E0596]: cannot borrow data in a `&` reference as mutable
 --> src/main.rs:8:13
  |
8 |     set_bit(&mut s, 0);
  |             ^^^^^^ cannot borrow as mutable
Code 2: エラー内容

原因

as_bytes()の定義を確認すると、

pub const fn as_bytes(&self) -> &[u8]

as_bytes() の返り値はバイト配列への不変参照になるので、それを可変な変数に格納しても、 set_bit() でバイト配列には可変アクセスできないのでした。

Figure 1: as_bytes()とas_bytes_mut()の違い

Figure 1: as_bytes()とas_bytes_mut()の違い

解決策

今回の場合、unsafeなas_bytes_mut()を使用することで、バイト配列への可変参照を取得できます。

最終的には下記のようなソースにすることで、コンパイルが通ります。

fn main() {
    let mut src = "abc".to_string();
    let mut s = unsafe { src.as_bytes_mut() };

    println!("{:08b}", &s[0]);
    set_bit(&mut s, 0);
    println!("↓");
    println!("{:08b}", &s[0]);
}

fn set_bit(bytes: &mut [u8], bit: usize) {
    bytes[bit / 8 as usize] |= 0x80 >> (bit % 8);
}
Code 3: 修正したコード

出力結果:

01100001
↓
11100001
Code 4: 出力結果

まとめ

Rustを書き始めたときはちんぷんかんぷんでしたが、最近はメモリの状態を意識しながら書くことに慣れてきました。こういうしょうもないエラーもたまにやってしまいますが、トラブルシューティングはかなりスムーズにできるようになってきた気がします。