String and std::ops:add

Hello,

I’m very suprise that this code do not compile:

let s1 = String::from("Hello, ");
let s2 = String::from(“world!”);
let s3 = s1 + &s2;
println!(“s1 is {}”, s1);

I understand that the std::ops::add take ownership for i32 and others because they are not moved but copied for performance reason.
In this case, the s1 string is moved ( String do not implement the Copy trait ). This means s1 will be dropped ( free the memory ) at the end of std::ops:add.
In an addition s1 and s2 are not modified, they do not need to take ownership ( both of them )
Is there any reason why String do not implement the std::ops::add by taking an self immutable reference?

Thank you,

The reasoning for this is described in the docs (although it’s on the implementation block, which isn’t always displayed by default in Rustdoc):

This consumes the String on the left-hand side and re-uses its buffer (growing it if necessary). This is done to avoid allocating a new String and copying the entire contents on every operation, which would lead to O(n^2) running time when building an n-byte string by repeated concatenation.

So your point about neither string being modified is not true - s2 remains the same, but s1's buffer is used for the new string. If the operation took the left hand side by reference, a new string would have to be allocated for the add every time - rather than making this expensive operation the default, you can opt in to it by manually cloning the left hand string.

1 Like

Ok I see.
So I can concatenate s1 and s2 strings without losing s1 by cloning s1 or maybe you know a better approch than the following?

let s1 = String::from("Hello, ");
let s2 = String::from(“world!”);
let s3 = s1.clone() + &s2;
println!(“s1 is {}”, s1);

That’s actually exactly the approach they show in the docs for when you want to keep the original string :slight_smile:

OK :slight_smile:
RTFM but actually I read the book :smiley:
Thank you !

1 Like

One that’s a bit unusual but extends nicely to more strings:

let s1 = String::from("Hello, ");
let s2 = String::from(“world!”);
let s3 = [&s1, &s2].concat();
println!(“s1 is {}”, s1);
1 Like