Lifetime problem: AsRef<str> vs &str

Hello dear rustaceans. I encountered another lifetime problem which I'm not sure I understand well.There are 2 version of functions lines() one expects &str and another one AsRef<str>. First one works, well, but second one "returns a value referencing data owned by the current function". While I think I understand the message, I don't understand how overcome the obstacle and use AsRef to make interface of function lines() more general.

The signature you want is

fn lines2<S: AsRef<str>>(src: &S) -> Lines<'_> {
    Lines::new(src.as_ref())
}

The signature of AsRef::as_ref() is fn as_ref(&self) -> &T, which means that calling it on a local variable does result in autoref and therefore a reference-to-local. (Consider e.g. S = String.)

If you pass an explicit reference in the first place, there's no need for the compiler to take a reference, as there already is one to begin with. So the as_ref() call will receive that reference as its self argument, and the same lifetime will apply to the return type.

Fixed playground.


By the way, if you are using many lifetime annotations just to accommodate a single, immutable reference, you are likely catastrophically overcomplicating it.

1 Like

Oh! Thank you for the answer. How does fn lines2<S: AsRef<str>>(src: &S) -> Lines<'_> that signature elided back? How does the same version with explicit lifetimes look like?

You actually want

fn lines2<S: AsRef<str> + ?Sized>(src: &S) -> Lines<'_>

// Without elision
fn lines2<'s, S: AsRef<str> + ?Sized>(src: &'s S) -> Lines<'s>

or else you can't pass, for example, a &str (because str is not Sized).

Or just taking &str is fine too.

3 Likes

Yes, you are right! Thank you. My mistake not using & before S.

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.