Help us understand the problem. What is going on with this article?

[Rust] 文字列をコピーせずに文字列の一部を置換する (in-place replacement)

Rustの文字列型にはreplaceというメソッドが実装されており、部分文字列の置換を行うことが出来る。
しかし、この関数は元の文字列を変更するのではなく、新たな文字列を生成するようだ。

この文字列の生成が無駄なように感じたので、Rustの練習も兼ねて元の文字列を書き換える関数を実装した。

実装

unsafe fn replace_inplace(s: &mut String, from: u8, to: u8) {
    let sv = s.as_bytes_mut();
    sv.iter_mut().filter(|x| **x == from).for_each(|x| *x = to);
}

使用方法

    let mut s = String::from("a\\b\\c");
    unsafe { replace_inplace(&mut s, b'\\', b'/'); }

    println!("{}", s);  // => "a/b/c"

ポイント

str型はas_bytes_mutメソッドを実装しており、このメソッドによってミュータブルなバイト列を取得できる。

let sv = s.as_bytes_mut();

しかし、これによって得られたバイト列を使えば、元の文字列を書き換えることが出来てしまう。しかももとの変数は借用されていないので、この関数を呼び出した後は、同じアドレスへの書き込み権限を有する変数が同時に2つ存在することになる。

したがって、いずれかの変数のライフタイムが切れるまではこのコードはunsafeであり、データ競合が起こらないように注意しなければならない。

例えば元の文字列を変更しようとした時に、メモリの再確保が行われるかもしれない。

// 文字列の長さを増やしているので、領域が足りない場合はメモリの再確保が行われる
s += "/d/e"

このとき、文字列の内部のデータのアドレスも新しいアドレスに置き換わるので、svが指すアドレスはもはや有効なアドレスではなくなる。またこの逆のパターン(取得したバイト列のメモリの再確保)もあるので注意しよう。

追記 (2019/7/16)

  • 変数の借用についての記述を修正
  • この実装だとUTF-8シークエンスを破壊する可能性があるので、関数自体をunsafeに変更

おわりに

今回は1文字だけの置換だったが、もっと複雑な置換も実装してみたいと思う。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした