問題の背景
Rustでは、主に2つの文字列タイプ — &str (不可変のスライス文字列、通常は文字列リテラル)と String (動的に変更可能な文字列)を区別します。言語の初期段階でのこれらの選択により、効率的なメモリ管理が簡素化され、厳格な所有権と参照システムによりテキストデータ処理における型の安全性が向上しました。
問題点
多くの開発者は、これらのタイプ間での相互作用に混乱します。例えば、文字列リテラルは &'static str であり、コンパイル時に割り当てられた不変文字列への参照ですが、String は実行時にデータを動的に拡張して含むことができます。タイプ間の変換、所有権の正しい使用、不要なコピーを避ける方法について疑問が生じます。
解決策
&str と String の間の変換は、所有権の基本ルールを理解していれば透明です:
String からスライスを取得するには、参照(my_string.as_str())または単純な借用(&my_string)を使用できます。&str を String に変換するには、to_string() または String::from() を使用します。コード例:
fn main() { let s_literal: &str = "hello"; let s_string: String = String::from(s_literal); let s_slice: &str = &s_string; let new_string = s_slice.to_string(); println!("{} {}", s_string, new_string); }
主な特徴:
&str はヒープにメモリを占有せず、常に不変です。String は動的にメモリを割り当て、変更可能です。Rustで文字列リテラルを変更できますか?
できません。文字列リテラル(&'static str)は常に不変であり、文字を変更しようとするとコンパイル時にエラーが発生します。
&strの上で.to_string()を呼び出すだけで、不要なコピーなしに可変文字列を得られますか?
いいえ、.to_string()は新しいメモリを常に割り当て、内容をコピーします。スライスに基づいて可変文字列が必要な場合、これは避けられません。
Stringから&strの参照を、ライフタイムの漏れのリスクなしに取得できますか?
はい、そのように取得した参照(let s: &str = &my_string;)は元のStringより長く生きません。関数からローカルStringへの&strを返そうとすると、ライフタイムエラーが発生します。
String の &str への参照を保持すること&str を String に変換すること(余分な割り当て)String::from("text") がデータをコピーしないと期待すること関数が関数体内の一時的なStringを参照する&strを返す場合:
fn faulty() -> &str { let s = String::from("Oops"); &s // ライフタイムエラー! }
メリット:
デメリット:
関数がすぐにStringを返し、呼び出し側に所有権を渡す:
fn correct() -> String { String::from("Safe!") }
メリット:
デメリット: