Newtype pattern with &str

I'm using a lot the newtype pattern to add type semantics to my code.
But I have been stucked with the following issue:

#[derive(PartialEq, Eq)]
pub struct ItemName(String);

impl From<&str> for ItemName {
    fn from(str: &str) -> Self {
        ItemName(str.to_string())
    }
}

fn main() {
    let vec: Vec<ItemName> = Vec::new();
    vec.push("Apple");
    assert!(vec.contains("Apple"));
}

Which raise the error:

error[E0308]: mismatched types
  --> src/main.rs:12:14
   |
12 |     vec.push("Apple");
   |              ^^^^^^^ expected struct `ItemName`, found `&str`

error[E0308]: mismatched types
  --> src/main.rs:13:26
   |
13 |     assert!(vec.contains("Apple"));
   |                          ^^^^^^^ expected struct `ItemName`, found `str`
   |
   = note: expected reference `&ItemName`
              found reference `&'static str`

Rust playground : Rust Playground

For some reason the compiler doesn't understand that the vec only contains ItemName and so that he can use the Form<&str> implementation to convert the &str to ItemName. How can I solve this issue?

It is not possible to make the compiler do this conversion automatically. You must explicitly add a call to a conversion function:

vec.push(ItemName::from("Apple"));
// or
vec.push("Apple".into());
4 Likes

Vec::push could have been defined like so:

fn push<U: Into<T>>(&mut self, item: U)

And then that would allow you to write .push("Apple"). However, it wasn't defined like that because that would mean this code would produce type inference errors:

let mut v = Vec::new();
v.push(3);

Rust wouldn't be able to figure out what type the vector contains, since it can be any type that i32 can be converted into, which is a lot of types.

So Rust makes the trade-off of requiring more explicit conversions in places in exchange for allowing fewer type annotations lots of the time.

2 Likes

You can convert a &str into an ItemName by calling any arbitrary function. Compiler can't know which function you want to execute, unless you type it.