1

I'm trying to write a trait on the String type that will allow it to concatenate Bar to any other string.

I know what the solution is but I'm not sure why it works. Could someone please explain the theory underlying the syntax for me?

// problematic code
// error[E0308]: mismatched types
// rustc --explain E0308
fn append_bar(self) -> String {
  self + String::from("Bar")
}

// solution
fn append_bar(self) -> String {
  self + &String::from("Bar")
}

The full script is below.

trait AppendBar {
    fn append_bar(self) -> String;
}

impl AppendBar for String {
    fn append_bar(self) -> String {
      self + String::from("Bar")
    }
}

fn main() {
    let s = String::from("Foo");
    let s = s.append_bar();
    println!("s: {}", s);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn is_FooBar() {
        assert_eq!(String::from("Foo").append_bar(), String::from("FooBar"));
    }

    #[test]
    fn is_BarBar() {
        assert_eq!(
            String::from("").append_bar().append_bar(),
            String::from("BarBar")
        );
    }
}
trent
  • 25,033
  • 7
  • 51
  • 90
Richard Jarram
  • 899
  • 11
  • 22

1 Answers1

4

The + operator is sugar for the add method of the std::ops::Add trait, and the implementation for String is:

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

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

That is, the right hand side of the + must be &str when the left hand side is a String.

However, due to deref coercion for function arguments, you can also pass a &String instead of a &str, because String implements Deref<Target = str>.

It's worth noting that a better "fix" for the exact code you provided is to avoid allocating a temporary String altogether, since "Bar" is already a &str:

fn append_bar(self) -> String {
    self + "Bar"
}

See also: Why is it discouraged to accept a reference to a String (&String), Vec (&Vec), or Box (&Box) as a function argument?

Peter Hall
  • 53,120
  • 14
  • 139
  • 204