Slice of AsRef<str>?

I am writing a library function which needs a list of strings passed, ownership not required.

As this is a library I would like to accept different inputs, for example a slice of &str's or a &Vec. The function (in due course) needs only a &[&str].

This is what I came up with:

fn myfunc<S: AsRef<str>>(strings: &[S]) {
    let strings = strings.iter().map(|s| s.as_ref()).collect::<Vec<_>>();
    let strings: &[&str] = &strings; // this is the type req'd by the function
    println!("{:#?}", strings);
}

#[tokio::main]
async fn main() {
    myfunc(&["a1", "a2", "a3"]);
    myfunc(&["b1".to_string(), "b2".to_string(), "b3".to_string()]);
    let v = vec!["c1", "c2", "c3"];
    myfunc(&v);
    let v = vec!["d1".to_string(), "d2".to_string(), "d3".to_string()];
    myfunc(&v);
}

Is there any other way to achieve this, especially without iterating for the transformation? The iteration builds a new Vec, which has a performance penalty and allocates memory, and I would prefer to avoid that.

If you have &[String] but the fn requires &[&str], fundamentally there's no way to avoid to construct another Vec<&str> from it. In this case there's no advantage to make this function generic. Just remove the generic and let user collect themselves only when needed.

Does it though? Will it be OK with taking impl IntoIterator<Item = S> with S: AsRef<str>, for example?

Yes, I need to pass on a &[&str] to other functions.

Makes sense if there really isn't any efficient way for the conversion, or at least a way to implement this where a &[&str] doesn't need to be converted.

I'm not clear on whether those other functions are your code or someone else’s, but either way I believe that in general, a &[&str] parameter type should be considered a design flaw, for precisely the reason that you are asking about; it essentially forces a temporary allocation. Code should always accept <S: AsRef<str>> ... &[S] instead — like you were doing but at all levels — because that allows the caller to have their choice of ownership of the string data.

(Of course, sometimes generics are not an feasible option.)

7 Likes

There's not: A String and a &str have different sizes.