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.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.