rustborrow-checkerrwlock

Rust "borrowed value does not live long enough" when iterating on RwLock


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.


Solution

  • 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