問題の歴史:
ネイティブ言語(C/C++)と比較して、Rustは参照タイプ(&str)と所有タイプ(String)の厳密な分離を通じて文字列の安全な操作を構築しています。これにより、メモリの不正使用、バッファオーバーラン、ダブルフリーに関連する多くのエラーを回避できます。
問題:
大人のGC言語とは異なり、Rustではどの文字列が誰の所有であり、どれくらいの期間生存するか、変更後にダングリング参照を取得しないようにするかを明確に理解する必要があります。UTF-8文字列の操作は、インデクシングと変更に注意が必要です。
解決策:
Rustでは、Stringは変更可能でヒープに割り当てられた文字列であり、その内容を所有しています。&strは、UTF-8であることが保証されたバイト列への不変参照です。必要に応じて、stdのメソッドを使用して安全に変換できます(&str -> Stringおよびその逆)。
コード例:
fn main() { let owned: String = String::from("Rust"); let borrowed: &str = &owned; let primitive: &str = "Hello"; // リテラルは常に&strです // &str -> Stringへの変換 let s: String = primitive.to_string(); // String -> &strへの変換 let st: &str = &s; println!("{} {} {} {}", owned, borrowed, primitive, st); }
主要な特徴:
&'static str型であり、Stringではありませんなぜ文字列をs[1]やs[i]のようにインデックス指定できないのですか?
Rustの文字列はUTF-8形式であるため、インデクシングは直接使用できません:s[i]はi番目の文字を返さず、時にはバイトの境界を超えてアクセスするとpanicを引き起こします。その代わりに、.chars().nth(i)や.get(start..end)メソッドを使用してください。
&strを安全に変更できますか?
できません — &strは常に不変スライスです。変更が必要な場合はto_owned/to_stringを行うか、String/Vec<u8>を使用してください。
String::from("abc")と"abc".to_string()は根本的に何が違いますか?
これらのオプションは結果としては等価であり、両方とも&strからデータをコピーしてStringを作成します。違いはスタイルにあり、例えばto_stringはToStringトレイトを介して実装されていますが、String::fromは「所有権を作成する」という意図をより明確に表現します。
関数がStringを受け取り、内部で不要な文字列のコピー(clone)を行い、別の関数にスライスを書き込み、ソースのライフタイムを延長するのを忘れました。結果:ダングリング参照&クラッシュ。
利点:
欠点:
関数が&strを受け取り、変更が必要な場合は内部で.to_string()を呼び出し、外部ではすべてのロジックを「ゼロコピー」のままにしています。ライフタイムは管理されており、余分な割り当てはありません。
利点:
欠点: