Kalle Svensson
Kalle Svensson

Reputation: 437

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?

Upvotes: 4

Views: 363

Answers (2)

Kalle Svensson
Kalle Svensson

Reputation: 437

The answer is that to_string() applied to a String is not a no-op; it is equivalent to clone(). The clone returned by to_string() is moved, whereas the original String is only borrowed for cloning and is never moved.

I approve jthulhu's answer even though I'm not sure it points out the actual reason for the behavior.

Upvotes: 1

jthulhu
jthulhu

Reputation: 8657

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.

Upvotes: 6

Related Questions