Lifetime issues with mutable borrow in a loop

⚓ Rust    📅 2026-01-01    👤 surdeus    👁️ 1      

surdeus

I'm working on refactoring code from owned data to borrowed data, and I've hit a lifetime issue with mutable borrows in a loop. The working version (with owned data) compiles fine, but the borrowed version fails.

The Problem:
I have a trait method that takes a mutable scratch space and returns an iterator. When the iterator borrows from the scratch space, I can't call this method multiple times in a loop:

fn ref_records<'point, 'scratch, ScratchT: ScratchSpaceRegistry>(
    &'point self,
    scratch: &'scratch mut ScratchT,
) -> RefIterResult<'point>  // Returns Result<Box<dyn Iterator<Item = RefRecord<'point>> + Send + 'point>, String>
where
    'scratch: 'point;

When I try to call this in a loop:

for point in data {
    let records = point.ref_records(scratch)?;
    Self::handle_point_ref(point, records, &mut inserter).await?;
}

Compiler Error:

cannot borrow `*scratch` as mutable more than once at a time
`*scratch` was mutably borrowed here in the previous iteration of the loop

The Working Version (for comparison):
This version works fine because the iterator doesn't borrow from scratch:

fn records<'point, 'scratch, ScratchT: ScratchSpaceRegistry>(
    &'point mut self,
    scratch: &'scratch mut ScratchT,
) -> OwnedIterResult  // Returns Result<Box<dyn Iterator<Item = Record> + Send>, String>
where
    'scratch: 'point;

The returned iterator contains owned Record values with no lifetime parameters, so the borrow of scratch ends immediately.

My Question:

Is there a way to express that the mutable borrow of scratch should only last as long as needed for deserialization, even though the returned iterator lives for 'point? Or is this a fundamental limitation where I need to restructure my API? If I need API restructuring, what would be a good way to handle this ?

The full code is available here: Rust Playground

I've tried various lifetime annotations but can't find a way to tell the compiler that scratch is only borrowed temporarily during iterator construction, not for the iterator's entire lifetime.

7 posts - 3 participants

Read full topic

🏷️ Rust_feed