2

In stdlib string.rs:

impl Add<&str> for String {
    type Output = String;

    #[inline]
    fn add(mut self, other: &str) -> String {
        self.push_str(other);
        self
    }
}


let s1 = String::from("tic");
let s2 = String::from("tac");

let s = s1 + &s2;// it works

s1 is immutable here, but Add::add(mut self, other: &str) is mut, I just want to know why.

Simson
  • 3,373
  • 2
  • 24
  • 38
wangliqiu
  • 369
  • 1
  • 9
  • 1
    AFAIK, `mut self` is different from `&mut self`, and your variable would have to be mutable only in the second case – ForceBru Jan 12 '21 at 11:13

2 Answers2

4

You borrow and consume s1 when you use it in the concatenation. If you try to print s1 after the line let s = s1 + &s2;// it works, there will be an error because it is used after move:

3 |     let s1 = String::from("tic");
  |         -- move occurs because `s1` has type `std::string::String`, which does not implement the `Copy` trait
...
6 |     let s = s1 + &s2;// it works
  |             -- value moved here
7 |     println!("{}{}{}",s,s1,s2);
  |                         ^^ value borrowed here after move

s1 does not need to be mutable as the variable is never mutated the data is moved and mutated to the variable s.

Cerberus
  • 8,879
  • 1
  • 25
  • 40
Simson
  • 3,373
  • 2
  • 24
  • 38
2
s1 is immutable here

Not exactly. The s1 binding is immutable, but since add takes ownership of the value it was bound to, it can do what it wants with it (including mutating it). As you don't have access to the value anymore you can't observe changes and it makes no difference to you.

It's not dissimilar to the meatworld: if you lend something to somebody and they have your permission to modify it then they might do so, but if you give something to somebody, whether they modify it is none of your business anymore.

As Simson notes, if you try to reuse s1 after the addition the compiler will reject your code.

Masklinn
  • 34,759
  • 3
  • 38
  • 57