rustownershipborrowing

String concatenation in rust and borrowing


I have been learning rust recently.

And I stumbled upon a snippet that is really bugging me.

Why does this work

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

And this does not?

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

Thank you in advance


Solution

  • From a technical standpoint, it's because String implements Add<&str> and Deref<Target=str>. So the compiler can rewrite your first example, s1 + &s2, into s1.add (s2.deref()).

    However neither &String nor &str implement Add, so the compiler can't rewrite &s1 + … into (&s1).add (…).

    From a language design standpoint, this choice was made because s1 + … may be done without allocation if there is enough space already allocated after the current contents of s1, but &s1 + … would always require an allocation and it was decided to make that allocation explicit. If you want to keep using the original s1 after the operation, you need to either clone it explicitly:

    let s3 = s1.clone() + &s2;
    

    or if performance is really that critical, you need to pre-allocate enough memory to hold the result:

    let s3 = String::with_capacity (s1.len() + s2.len()) + &s1 + &s2;