Rustで&strとStringを相互に変換
Rustで文字列スライス&str
と文字列String
を相互に変換する方法について説明する。
説明のため、変数の型の名前を返す以下の関数を用いる。
- 関連記事: Rustで変数の型の名前を取得・確認
fn type_of<T>(_: &T) -> &'static str {
std::any::type_name::<T>()
}
&strをStringに変換
&str
をString
に変換(&str
からString
を生成)するには以下の方法がある。
to_owned
to_string
String::from
into
Rust1.9
(2016年5月)まではto_string
が遅いという違いがあったが、1.9
以降はすべて同じ性能。
As of Rust 1.9,
str::to_string
,str::to_owned
,String::from
,str::into
all have the same performance characteristics. Use whichever you prefer. What is the difference between these 3 ways of declaring a string in Rust? - Stack Overflow
どれを使うかは好みの問題ではあるが、&str
とString
の違いは所有権を持つかどうかであり、to_owned
が処理の意図をより明確に表しているという意見がある。
- to_string() vs to_owned() for string literals - help - The Rust Programming Language Forum
- Clippy Lints - str_to_string
とはいえ、初心者にとってはto_owned
よりto_string
やString::from
のほうが意味を理解しやすいので、場合によって好きなものを使えばよいだろう。
to_owned
to_owned
メソッドはToOwned
トレイトで実装されている。
let s_str = "abc";
assert_eq!(type_of(&s_str), "&str");
let s_string = s_str.to_owned();
assert_eq!(type_of(&s_string), "alloc::string::String");
to_string
to_string
メソッドはToString
トレイトで実装されている。
let s_string = s_str.to_string();
assert_eq!(type_of(&s_string), "alloc::string::String");
中身はString::from
。
impl ToString for str {
#[inline]
fn to_string(&self) -> String {
String::from(self)
}
}
String::from
String::from
はFrom
トレイトで実装されている。
let s_string = String::from(s_str);
assert_eq!(type_of(&s_string), "alloc::string::String");
中身はto_owned
。
impl From<&str> for String {
/// Converts a `&str` into a [`String`].
///
/// The result is allocated on the heap.
#[inline]
fn from(s: &str) -> String {
s.to_owned()
}
}
into
From<&str> for String
が実装されているので、対応するInto
トレイトが自動的に実装され、&str
からString
を生成するinto
メソッドが使える。
String
以外の型に対してもFrom<&str> for T
が実装されているので、String
に変換したい場合はinto
の返り値の型がString
だと推論可能でなければならない。let
の場合は型注釈が必要。
// let s_string = s_str.into();
// error[E0282]: type annotations needed
let s_string: String = s_str.into();
assert_eq!(type_of(&s_string), "alloc::string::String");
Stringを&strに変換
仮引数&strに対しては&Stringを渡せばよい
仮引数の型が&str
の関数に対しては&String
(String
の参照)を渡せる。明示的に&str
に変換する必要はない。
fn test_func(s: &str) -> usize {
s.len()
}
let s_string = String::from("abc");
assert_eq!(test_func(&s_string), 3);
これは&String
が&str
に型強制されるから。詳細は以下の記事を参照。
as_str
as_str
メソッドでString
を&str
に変換できる。
let s_str = s_string.as_str();
assert_eq!(type_of(&s_str), "&str");
スライス
文字列スライス&str
は文字通り文字列のスライスなので、[..]
で全体のスライスを指定することでString
から&str
を得られる。
let s_str = &s_string[..];
assert_eq!(type_of(&s_str), "&str");
参照
上述のように、&String
は&str
に型強制される。
型強制は型が明示された(型注釈が記述された)let
文でも起こる。
したがって、&str
と型注釈したlet
文で&String
から&str
を定義できる。
let s_str: &str = &s_string;
assert_eq!(type_of(&s_str), "&str");
型注釈が無い場合は型強制されず&str
ではなく&String
になるので注意。
let s_string_ref = &s_string;
assert_eq!(type_of(&s_string_ref), "&alloc::string::String");