I understand what the code does, but I don't understand what the code is trying to achieve. If an Rc
is unique, can't I just .try_unwrap()
.unwrap()
it? And after passing it to a different thread, you could create a new Rc
around it.
Hmmm, now that I think about it, is this to avoid the costs of allocating the Rc
? Then it makes sense to me.
That would mean when sending the value, an actual action would have to be performed automatically. I don't think this is possible in Rust, but I'm curious if I'm wrong.
What I think could be done is cloning the String
manually, this way:
use std::rc::Rc;
use std::thread::{JoinHandle, spawn};
fn sub_task(rc: &Rc<String>) -> JoinHandle<()> {
// We clone the `String` manually:
let to_be_sent = String::clone(rc);
spawn(move || {
// We can turn the cloned `String` back into `Rc`s:
let rc3 = Rc::new(to_be_sent);
let rc4 = rc3.clone();
// And some debug output:
println!("Inside thread: {rc3}, {rc4}");
})
}
fn main() {
// Let's assume we get an allocated `String` from somewhere:
let s = String::from("ABC");
// We turn it into an `Rc`:
let rc1 = Rc::new(s);
// We can clone the `Rc` without copying the `String` itself:
let rc2 = rc1.clone();
// Let's use one of the `Rc`s for a task that will be executed in another thread:
let thread = sub_task(&rc1);
// And some debug output:
println!("Outside thread: {rc1}, {rc2}");
// Joining the other thread:
thread.join().expect("thread panicked");
}
(Playground)
Output:
Outside thread: ABC, ABC
Inside thread: ABC, ABC
P.S.: In order to make the code more abstract, you might also use the *
operator instead of calling String::clone
(to be independent on String
and have the code work with any type that is Clone
):
- let to_be_sent = String::clone(rc);
+ let to_be_sent = (**rc).clone();
(Playground)
The first *
dereferences the shared reference, the second *
dereferences the Rc
, thus giving the inner value (which then gets cloned instead of cloning the Rc
).
Another variant that might be more verbose (and less confusing):
+use std::ops::Deref;
fn sub_task(rc: &Rc<String>) -> JoinHandle<()> {
// We clone the `String` manually:
- let to_be_sent = String::clone(rc);
+ let to_be_sent = Rc::deref(rc).clone();
(Playground)