This works:
let hello = "Hello ".to_string();
let world = "world!";
let hello_world = hello + world;
But this doesn't:
let hello = "Hello ".to_string();
let world = "world!".to_string();
let hello_world = hello + world;
But this does:
let hello = "Hello ".to_string();
let world = "world!".to_string();
let hello_world = hello + &world;
Is that because the String
needs a pointer to the original string slice of the second String
? If so, why?
The answer is in two parts.
The first part is that +
involves using an Add
trait implementation. It is implemented only for:
impl<'a> Add<&'a str> for String
Therefore, string concatenation only works when:
String
&str
Note: unlike many other languages, addition will consume the Left Hand Side argument.
The second part, therefore, is what kind of arguments can be used when a &str
is expected?
Obviously, a &str
can be used as is:
let hello = "Hello ".to_string();
let hello_world = hello + "world!";
Otherwise, a reference to a type implementing Deref<&str>
will work, and it turns out that String
does so &String
works:
let hello = "Hello ".to_string();
let world = "world!".to_string();
let hello_world = hello + &world;
And what of other implementations? They all have issues.
impl<'a> Add<String> for &'a str
requires prepending, which is not as efficient as appendingimpl Add<String> for String
needlessly consume two arguments when one is sufficientimpl<'a, 'b> Add<&'a str> for &'b str
hides an unconditional memory allocationIn the end, the asymmetric choice is explained by Rust philosophy of being explicit as much as possible.
Or to be more explicit, we can explain the choice by checking the algorithmic complexity of the operation. Assuming that the left-hand side has size M and the right-hand side has size N, then:
impl<'a> Add<&'a str> for String
is O(N) (amortized)impl<'a> Add<String> for &'a str
is O(M+N)impl<'a, 'b> Add<&'a str> for &'b str
is O(M+N)impl Add<String> for String
is O(N) (amortized)... but requires allocating/cloning the right-hand side for nothing.The standard library implements the following:
impl<'a> Add<&'a str> for String
Which is exactly what you have noticed, you can only add a &str
to a String
.
This has these Advantages:
&str
slice&String
(as it dereferences to &str)If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With