0

I have the following code which fails to compile because it says the borrowed value does not live long enough:

        struct Node {
            val: RwLock<f32>,
            next: RwLock<Option<Arc<Node>>>,
        }

        impl Node {
            pub fn traverse(&self) {
                let mut current_node = self;
                loop {
                    let guard = current_node.next.read().unwrap();
                    let val = &*guard;
                    {
                        let next_node = match val {
                            Some(node) => node,
                            None => break,
                        };

                        println!("{:?}", *current_node.val.read().unwrap());
                        current_node = next_node;
                    }
                }
            }
        }

I don't understand why, though. FWIU both guard and val are valid for the duration of the scope of the loop iteration. Yet the compiler says:

    |
150 |                     let val = &*guard;
    |                                 ^^^^^ borrowed value does not live long enough
...
160 |                 }
    |                 -
    |                 |
    |                 `guard` dropped here while still borrowed
    |                 borrow might be used here, when `guard` is dropped and runs the `Drop` code for type `RwLockReadGuard`

What exactly is going on? How could the borrow be used when guard is dropped and is there a way to fix this?

I tried to get the guard and the val outside of the loop, and tried to put a scoped block inside, not sure what else to try.

cafce25
  • 15,907
  • 4
  • 25
  • 31
astinov
  • 3
  • 1
  • 3
    You're setting `current_node` to `next_node`, which is a reference into `val`, which is a reference into `guard`. However, `guard` is dropped at the end of the loop iterations, so `next_node` can't live longer than it. – PitaJ Apr 05 '23 at 19:59
  • Thanks @PitaJ but taking the guard outside of the loop is something I tried and the error is the same. Any suggestion on how to fix this? – astinov Apr 05 '23 at 20:31

1 Answers1

2

You can resolve this by storing Arc<Self> in current_node.

use std::sync::{RwLock, Arc};

struct Node {
    val: RwLock<f32>,
    next: RwLock<Option<Arc<Node>>>,
}

impl Node {
    pub fn traverse(self: Arc<Self>) {
        let mut current_node = self;
        loop {
            current_node = {
                let guard = current_node.next.read().unwrap();
                println!("{:?}", *current_node.val.read().unwrap());
                
                match &*guard {
                    Some(node) => Arc::clone(node),
                    None => break,
                }
            };
        }
    }
}

playground

PitaJ
  • 12,969
  • 6
  • 36
  • 55
  • 2
    And with a bit of imagination and an extra variable you can make it compile taking a `&self` argument instead of `Arc`: [playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=59c20e3f67aa3d2d14b8dcd434d26641). – rodrigo Apr 05 '23 at 20:54