所有権? String と 文字列スライス
文字リテラル Hello から String を作成し、一部を文字列スライスとして切り出した後、String スコープ外で文字列スライスを使う。というシナリオを考えたが、以下のようにコンパイルエラーが発生する。文字列スライスが参照している大元の String がスコープを抜ける際に Drop してしまうためだ。
fn main() { let sub: &str; { let s = String::from("Hello"); sub = &s[0..2]; // ^ borrowed value does not live long enough } println!("{}", sub); // --- borrow later used here }
文字列スライスを clone() すれば行けるか?と思ったが、文字列スライスは clone() メソッドを実装していないようだ。同様に copy() メソッドも実装されていなかった。
fn main() { let sub: &str; { let s = String::from("Hello"); sub = &s[0..2].clone(); // ^^^^^ method not found in `str` } println!("{}", sub); }
一度文字列スライスから String を作成し、それを as_str() で再度文字列スライス化しても、新たに生成した String はスコープを抜ける際に Drop() されてしまうので、同じだった。
fn main() { let sub: &str; { let s = String::from("Hello"); sub = String::from(&s[0..2]).as_str(); // ^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement // | // creates a temporary which is freed while still in use } println!("{}", sub); // --- borrow later used here }
文字列スライスを取得するのをあきらめて、文字列スライスを String にしたものを取得するようにすると、コンパイルが通る。
fn main() { let sub: String; { let s = String::from("Hello"); sub = String::from(&s[0..2]); } println!("{}", sub); }
to_string() のほうが String::from() より簡潔に書けてよさそう。
fn main() { let sub: String; { let s = String::from("Hello"); sub = s[0..2].to_string(); } println!("{}", sub); }
というか、今回の例ではこれでもいいのか。簡潔に書きすぎて、いったい何がしたいんだ。。。というコードになるけど。。。
fn main() { let sub: String; { sub = "Hello"[0..2].to_string(); } println!("{}", sub); }