Assignment requires that `'1` must outlive `'str`

Hello. Can you please help me to fix an issue in the bellow code. This is a simplified version of a code that I need to implement in my project.

struct StrHolder<'str> {
    text: String,
    ptrToText: Option<&'str String>,
}
impl <'str> StrHolder<'str> {
    fn setPtr(& mut self) {
        self.ptrToText = Option::Some(&self.text);
    }
}
fn main() {
    let mut holder = StrHolder {
        text: String::from("asdada"),
        ptrToText: Option::None,
    };
    holder.setPtr();
    println!("{}", holder.ptrToText.unwrap())
}

so I have the method ''setPtr' which does some computation with a text and store a result as a pointer into the ptrToText.
The below code is not compiled with error "assignment requires that '1 must outlive 'str"
I can change method to "fn setPtr(&'str mut self)" but in this case I receive error in the line "println!("{}", holder.ptrToText.unwrap())"

^^^^^^^^^^^^^^^^
| |
| use of borrowed holder
| borrow later used here

I wonder if it is possible to fix this code. Thanks in advance

You are trying to make a self-referential type. That is not possible in safe Rust (as the reference to the text field would be invalidated if the instance of StrHolder were moved.). Re-organize your data so you don't have to.

you are creating self referential data structure, which is not trivial to do in rust, it's strongly advised against, and you'll easily get undefined behavior when done wrong.

basically you need to Pin your struct first, then you use raw pointer instead of regular borrow.

I think you'd better describe your problem in context and people can give your better advices, and self referential problem can be avoided in the first place.

Thanks a lot. Is my understanding correct that in my example I can't set ptrToText using only a safe code?

You can't correctly set it with unsafe as-is, either. You should probably split up your type to owned and borrowed halves, or use Rc.

Thanks. Can you please elaborate a bit more on a Rc version?

I found a thread with exactly of my problem: Ownership and mutable borrow in same struct

But the provided solution is not suitable for me. That is why: I have a GUI application where a user fetches let's say first 20 rows from a database. The user later can request next 20 rows and so on. The application need some how to store RowIter between user's interactions.
I know that I can fetch all rows to a vec and store the vec instead of RowIter but storing all rows in memory is not feasible.

so you want fetch each 20 rows in batch lazily, do I understand it correctly? you don't need to be self referential, just keep track of how many rows you already fetched, and fetch a new batch on demand. something like:

struct CachedRows<'b> {
    fetcher: RowIter<'b>,
    cache: Vec<Row>,
}

impl CachedRows<'_> {
    /// fetch next batch to fill cache, return more is available
    fn fill_cache(&mut self) -> bool {
        // or if the inner `RowIter` supports batch fetch, you can replace the loop with e.g.
        // self.cache.extend(self.inner.batched(20));
        self.cache.reserve(20);
        for _ in 0..20 {
            let Some(row) = self.fetcher.next() else {
                return false;
            };
            self.cache.push(row);
        }
        true
    }
    fn get(&mut self, index: usize) -> Option<&Row> {
        while index >= self.cache.len() && self.fill_cache() {
        }
        self.cache.get(index)
    }
}

you can only cache the "current" batch and discard previous rows, you need to keep track of the start index of "current" batch. depending on your use cases, interior mutability might be needed.

another possible solution for the "either reference or owned value" is to use Cow, for example, Cow<str> can store either a borrowed str slice, or an owned String value, and it deferrers to &str so when you use the string, you can just treat it like a regular str slice.

the type to put in a Cow must implement ToOwned, and the standard library has provided implementation for str, CStr, OsStr, Path, and for generic [T] and T: Clone

the Clone bounds ensures that you can always get an owned value from a borrowed reference (see Cow::into_owned()). but if your custom type is not Clone, you can always create your own enum similar to Cow which doesn't need to give out an owned value.

you can also implement Iterator for your wrapper type, so basically you make an lazy iterator adapter with cache, similar to std::iter::Peekable, just Peekable can only cache one item a time (a.k.a. look ahead).

Thanks a lot for your answer.
My main problem is that I don't understand how to store RowIter<'b> between user's interactions. RowIter<'b> stores pointer to Client inside, that is why it has 'b.
I thought that I need to wrap a RowIter and a Client to struct MyPgData and store them together where MyPgData will own client and RowIter will have a reference to this Client.

struct MyPgData<'a> {
    client: Client,
    iter: Option<RowIter<'a>>,
}

No, don't do that. Separate the iterator from the data you are iterating over if your data is borrowed.

1 Like

as suggested by @H2CO3 don't borrow data that is owned by yourself. think carefully about ownership.

ownership manages resources. e.g. I assume Client represents connection to some database, so ownership here means when the Client is dropped, the database connection is cleaned up.

borrows can be thought of "views" to the owned data, and iterators encapsulate (most likely mutable) transient states required to do iteration over the borrowed data. for instance, to iterator over a slice, the iterator must at least track the current index.

typically, a pager type should not own the database connection, and in your example, the RowIter borrows the Client, so I assume the RowIter is not intended to be stored long term. I don't know exactly how the library is designed, but my intuition is, if your pager UI doesn't live long, e.g a modal dialog that pops up when the user clicked some button, it's probably fine to associate the RowIter with your UI states.

however, if your pager UI is long lived, i.e. non-modal, or it's just your app's main interface, then you should cache the database query result anyway, and your UI component should interact with the cache layer, not directly to the database connection.

another thought is, does your database library allow you to create an iterator with arbitrary queries? if so, you don't need to store the RowIter at all, you just need to create a local iterator when you refill your cache, and then drop it.