Which type should I accept in factory function?

Let's assume we have struct.

struct User {
    name: String,
}

Which impl is preferred?

impl User {
    fn new<N: AsRef<str>>(name: &N) -> Self {
        User {
            name: name.as_ref().to_owned(),
        }
    }
}

or

impl User {
    fn new(name: String) -> Self {
        User {
            name: name,
        }
    }
}

I think that second form is more clear to user.

The second form is generally better because:

  1. it allows you to plug in an existing string on the heap if you have one and don't mind losing ownership of it
  2. it makes the potentially expensive operation explicit in the caller.

If you have a lot of call sites (tens), then ergonomics becomes a consideration, although it will be a case-by-case thing.

1 Like

If allocations are an issue, you can also consider putting a &str or a Cow<str> into the struct.

The following is a little more complex, but it may lead to a nicer API

impl User {
    fn new<T: Into<String>>(name: T) -> Self {
        User { name: name.into() }
    }
}

See clap for an example of a very nice API

1 Like