rustborrow

Why does calling .to_string() on a String avoid a move error? Isn't it a no-op?


The following test program would not compile:

fn f1( string: String) {
    println!("{}", string );
}

fn f2( string: String) {
    println!("{}", string );
}

fn main() {
    let my_string: String = "ABCDE".to_string();
    f1( my_string );
    f2( my_string );
}

It generates the well-expected error:

11 |     f1( my_string );
   |         --------- value moved here
12 |     f2( my_string );
   |         ^^^^^^^^^ value used here after move

However, if you treat my_string with the to_string() method, the program compiles and works. to_string() should be a no-op method since my_string is a String already. However, this programs works fine.

fn f1( string: String) {
    println!("{}", string );
}

fn f2( string: String) {
    println!("{}", string );
}

fn main() {
    let my_string: String = "ABCDE".to_string();
    f1( my_string.to_string() );
    f2( my_string.to_string() );
}

How does the rust theory explain this paradox?


Solution

  • The ToString::to_string method requires a &str, which is Copy, therefore it can be moved out while keeping ownership (because &T: Copy for T: ?Sized, see the documentation).

    On the other hand, String does not implement Copy, which means once the value is moved, its ownership has been given away.