Differeence regarding lifetimes

pub fn cursor(s:&str)-> Cursor<'_> {
    Cursor::new(s)
}

pub struct Cursor<'a> {
    chars: Chars<'a>,
}

impl<'a> Cursor<'a> {
    pub fn new(input: &'a str) -> Cursor<'a> {
        Cursor {
            chars: input.chars()
        }
    }

    pub fn as_str(&self) -> &'a str {
        self.chars.as_str()
    }
}
pub fn cursor(s:&str)-> Cursor<'_> {
    Cursor::new(s)
}

pub struct Cursor<'a> {
    chars: Chars<'a>,
}

impl Cursor<'_> {
    pub fn new(input: &str) -> Cursor<'_> {
        Cursor {
            chars: input.chars()
        }
    }

    pub fn as_str(&self) -> &str {
        self.chars.as_str()
    }
}

Pls explain difference between both cases(notice 2 lifetimes removed of 1).
In one of codebase doing so caused lifetime issues (that codebase had single lifetime).

This one is elided to

pub fn as_str<'b>(&'b self) -> &'b str { ... }

instead of

pub fn as_str<'b>(&'b self) -> &'a str { ... }

as in your first example.

1 Like

We can further expand that, not just eliding the lifetimes but also replacing the self sugar with the actual parameter type:

pub fn as_str(self: &'b Cursor<'a>) -> &'b str

The returned &str contains the lifetime of a borrow of a Cursor instead of the borrow of the original str the Cursor was created with. Thus, you only get to use it as long as your borrow of the Cursor exists, which is more restrictive than returning &'a str that can outlive the borrow of the Cursor (and outlive the Cursor itself too).

1 Like

so which one is right in general scenarios

All choices in function signatures are tradeoffs between what they allow the caller to do and what they allow the callee to do.

-> &'a str gives more flexibility to the caller, but means as_str() can't ever return a borrow of data the Cursor owns. For a cursor type that borrows input, that's probably the right choice.

1 Like

so returned str is related to original str lifetime instead of this fn's &self's lifetime

thank you very much both of you

In the first example, yes.