0

I am trying to write a binary tree that can be passed around between threads without having to be copied every time. I'm having a hard time understanding how to do this with Rust's restrictions around lifetimes.

use std::thread::spawn;

#[derive(Debug)]
struct Node<'a> {
    left: &'a i32,
    right: &'a i32,
}

fn main() {
    let l = 3;
    let r = 4;
    let n = Node {
        left: &l,
        right: &r,
    };

    spawn(|| {
        println!("{:?}", n);
    });
}
error[E0597]: `l` does not live long enough
  --> src/main.rs:13:15
   |
13 |           left: &l,
   |                 ^^ borrowed value does not live long enough
...
17 | /     spawn(|| {
18 | |         println!("{:?}", n);
19 | |     });
   | |______- argument requires that `l` is borrowed for `'static`
20 |   }
   |   - `l` dropped here while still borrowed

error[E0597]: `r` does not live long enough
  --> src/main.rs:14:16
   |
14 |           right: &r,
   |                  ^^ borrowed value does not live long enough
...
17 | /     spawn(|| {
18 | |         println!("{:?}", n);
19 | |     });
   | |______- argument requires that `r` is borrowed for `'static`
20 |   }
   |   - `r` dropped here while still borrowed

error[E0373]: closure may outlive the current function, but it borrows `n`, which is owned by the current function
  --> src/main.rs:17:11
   |
17 |     spawn(|| {
   |           ^^ may outlive borrowed value `n`
18 |         println!("{:?}", n);
   |                          - `n` is borrowed here
   |
note: function requires argument type to outlive `'static`
  --> src/main.rs:17:5
   |
17 | /     spawn(|| {
18 | |         println!("{:?}", n);
19 | |     });
   | |______^
help: to force the closure to take ownership of `n` (and any other referenced variables), use the `move` keyword
   |
17 |     spawn(move || {
   |           ^^^^^^^

I understand why it would think they don't live long enough, but how should I restructure this so that they do?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366

1 Answers1

3

In your situation, you create a Node object with references to variables you defined in your main() function, and pass it to a new thread. The problem is that you have absolutely no guarantee that this thread will finish before the thread of your main(), and you risk your original variables going out of scope before the references, hence the error.

Given that you wish to build a tree, I think the easiest fix would be to have your Node type own its fields, like this:

#[derive(Debug)]
struct Node {
    left: i32,
    right: i32,
}

you will then have no more lifetime issues.

To share it between several threads without copying it, you can use the std::sync::Arc wrapper; it's for exactly this purpose. You can do something like:

use std::sync::Arc;

fn main() {
    let n = Arc::new(Node { left: 3, right: 4 });

    for _ in 0..10 {
        let n_thread = n.clone();
        spawn(move || {
            println!("{:?}", n_thread);
        });
    }
}

If you need to give your other threads write access to the Node as well, you probably will want to wrap it in a Mutex or a RwLock, keeping whole thing inside an Arc.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Levans
  • 14,196
  • 3
  • 49
  • 53