Rust における String 型と &str の使い分けについて

 

1. String 型とは

  • 所有権を持つ文字列型
    • ヒープ領域に格納される可変長文字列。
    • 動的に文字列を追加・削除・変更できる。
  • 主に以下の場合に使う:
    • 新しい文字列を生成する。
    • 既存の文字列を加工する。
    • 他の関数や構造体に所有権を渡したい場合。

例: String の基本操作

fn main() {
    let mut s = String::from("Hello");
    s.push_str(", world!"); // 文字列を追加
    println!("{}", s); // 出力: Hello, world!
}

2. &str 型とは

  • 文字列スライス (参照型)
    • Stringリテラル文字列 ("abc") を借用して参照する形式。
    • 軽量で効率的(所有権を持たないためコピーは不要)。
    • イミュータブルなため、変更はできない。
  • 主に以下の場合に使う:
    • 短命の文字列参照。
    • 関数の引数として文字列を借用する。

例: &str の基本操作

fn main() {
    let s = "Hello, world!"; // 文字列リテラルは `&str`
    println!("{}", s); // 出力: Hello, world!
}

3. String&str の違い

特徴 String &str
所有権 あり なし
データ位置 ヒープ スタックや他の場所
変更可能性 可能 不可能
用途 長期的または加工用 一時的または軽量操作用

4. String&str の相互変換

  • String&str: 借用で変換可能。
  • &strString: クローンして変換。

例: 相互変換

fn main() {
    let s = String::from("Rust");
    let slice: &str = &s; // `String` → `&str` (借用)
    println!("{}", slice);

    let literal = "Hello, world!";
    let owned_string = literal.to_string(); // `&str` → `String`
    println!("{}", owned_string);
}

5. 関数での使い分け

  • &str を引数に使う:
    所有権を移動せず、広範囲な入力を受け付ける。

  • String を引数に使う:
    関数内で所有権を取得し、文字列を操作する。

例: 関数での使い分け

fn print_str(s: &str) {
    println!("{}", s);
}

fn take_string(s: String) {
    println!("{}", s);
}

fn main() {
    let owned = String::from("Hello");
    let slice = "world";

    print_str(&owned); // `String` を借用
    print_str(slice);  // `&str` をそのまま渡す

    take_string(owned); // `String` の所有権を渡す
}

6. まとめ

  • String: 可変・所有権あり。文字列操作や所有権を渡す場合に使用。
  • &str: 不変・軽量。効率的な参照を行う場合に使用。
  • 必要に応じて相互変換を行い、適切な型を選択することが重要。