Collecting an iterator of AsRef<str> as Vec<&str>

Given a function like the one in the Playground snippet below that takes an IntoIterator of AsRef<str>, is it possible to construct a Vec<&str> from this iterator rather than Vec<String> (the goal being cutting down on unnecessary allocations)? I've tried .map(AsRef::as_ref) and manually pushing the results of as_ref() calls onto a Vec (the latter you can see commented out), but these give me compilation errors about the lifetime of the return values.

(I'd also appreciate any feedback on making the code more idiomatic, as I suspect that could be improved somehow.)

The signature of AsRef<T>::as_ref() is:

fn as_ref(&self) -> &T;

desugared:

fn as_ref<'a>(&'a self) -> &'a T;

meaning that the lifetime of the returned reference is tied to the lifetime of the reference to *self. Thus, if you have a type S: AsRef by-value, you can only use the returned reference as long as you hold onto the value, and no longer. Just think about it: if the type were S = String, for example, then being allowed to use the returned &str after the String is dropped would lead to a use-after-free error.

What you can do is enforce that the iterator return references in the first place:

fn and_join<'a, I, S>(strings: I) -> String
where I: IntoIterator<Item = &'a S>,
      S: ?Sized + AsRef<str> + 'a,
{
    ...
}

Complete code

6 Likes

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.