to_string
メソッドではレシーバの自動参照外しが行われません (※後述) 。
少なくともバージョン 1.55.0 現在は、&str
と &&str
で異なる to_string
が呼ばれます。
&str
のときは String::from
と同じ動作をしますが、&&str
の場合は違う動作をします。
-
self: &str
のとき:<str as ToString>::to_string
-
self: &&str
のとき:<T as ToString>::to_string
※ self: &&&str
以降の参照も <T as ToString>::to_string
1. LLVM IR で確認
let foo: &&str = &"Foo";
println!("{}", case_1(foo));
println!("{}", case_2(foo));
#[inline(never)]
fn case_1(foo: &&str) -> String {
<str as ToString>::to_string(*foo)
}
#[inline(never)]
fn case_2(foo: &&str) -> String {
<&str as ToString>::to_string(foo)
}
cargo install cargo-asm
cargo llvm-ir test::main::case_1 | grep ToString
cargo llvm-ir test::main::case_2 | grep ToString
br i1 %2, label %bb20.i.i.i.i.i.i.i.i.i.i.i, label %"<str as alloc::string::ToString>::to_string.exit"
"<str as alloc::string::ToString>::to_string.exit"
br i1 %3, label %bb1.i.i, label %"<T as alloc::string::ToString>::to_string.exit"
"<T as alloc::string::ToString>::to_string.exit"
参考「GitHub - gnzlbg/cargo-asm: cargo subcommand showing the assembly or llvm-ir generated for Rust code」
2. ToString
トレイトの実装
Display
トレイトは参照に対して再帰的にブランケット実装され、さらに Display
トレイトを実装する型に対して ToString
トレイトがブランケット実装されます。
参考「[Rust] to_string メソッド等は呼び出し時に自動参照外しされない - Qiita」
2.1. &str
の場合
バージョン 1.9.0 から、プリミティブ型 str
が独自に ToString
トレイトを実装し、String::from
と同じ動作をするようになっています。
impl ToString for str {
#[inline]
fn to_string(&self) -> String {
String::from(self)
}
}
参考「ToString - str - Rust」(ブランケット実装でないトレイト実装の方)
2.2. &&str
等の場合
少なくともバージョン 1.55.0 現在は &&str
等に対しては独自の実装はされず、Display
トレイトを実装する型がブランケット実装する ToString
トレイトの to_string
メソッドが呼ばれます。
Formatter
を介して String
のバッファに書き込まれます。
impl<T: fmt::Display + ?Sized> ToString for T {
// ... 略
#[inline]
default fn to_string(&self) -> String {
let mut buf = String::new();
let mut formatter = core::fmt::Formatter::new(&mut buf);
// Bypass format_args!() to avoid write_str with zero-length strs
fmt::Display::fmt(self, &mut formatter)
.expect("a Display implementation returned an error unexpectedly");
buf
}
}
参考「ToString - str - Rust」(ブランケット実装の方)
impl Display for str {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.pad(self)
}
}