Help regarding lifetimes with iter::repeat_with(...)

use std::iter;
use std::cell::RefCell;

#[derive(Debug)]
struct NoClone(usize);

fn main() {
    let mut foo = NoClone(0);
    {
        for mut bar in iter::repeat_with(|| &mut foo).take(1) {
            bar.0 += 1;
        }
    }
    
    println!("{:?}", foo);
}

fn work_around() {
    let mut foo = NoClone(0);
    {
        let bar = RefCell::new(&mut foo);
        for mut baz in iter::repeat_with(|| bar.borrow_mut()).take(1) {
            baz.0 += 1;
        }
    }
    
    println!("{:?}", foo);
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/main.rs:10:45
   |
10 |         for mut bar in iter::repeat_with(|| &mut foo).take(1) {
   |                                             ^^^^^^^^
   |
note: first, the lifetime cannot outlive the lifetime '_ as defined on the body at 10:42...
  --> src/main.rs:10:42
   |
10 |         for mut bar in iter::repeat_with(|| &mut foo).take(1) {
   |                                          ^^^^^^^^^^^
note: ...so that closure can access `foo`
  --> src/main.rs:10:45
   |
10 |         for mut bar in iter::repeat_with(|| &mut foo).take(1) {
   |                                             ^^^^^^^^
note: but, the lifetime must be valid for the expression at 10:24...
  --> src/main.rs:10:24
   |
10 |         for mut bar in iter::repeat_with(|| &mut foo).take(1) {
   |                        ^^^^^^^^^^^^^^^^^
note: ...so type `fn([closure@src/main.rs:10:42: 10:53 foo:&mut NoClone]) -> std::iter::RepeatWith<[closure@src/main.rs:10:42: 10:53 foo:&mut NoClone]> {std::iter::repeat_with::<&mut NoClone, [closure@src/main.rs:10:42: 10:53 foo:&mut NoClone]>}` of expression is valid during the expression
  --> src/main.rs:10:24
   |
10 |         for mut bar in iter::repeat_with(|| &mut foo).take(1) {
   |                        ^^^^^^^^^^^^^^^^^

error: aborting due to previous error

error: Could not compile `playground`.

To learn more, run the command again with --verbose.

Is it possible to solve the lifetime issues without using the work_around which comes with a runtime cost?

If it was possible to make this compile, you could just as easily do .take(2).collect() instead and get two aliasing references to foo, which is UB.

3 Likes

Ah ok this makes sense. So i have to use the work_around or do some unsafe code and make sure im not using something like collect.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.