/*
1. Why does the second println! output print LocalKey{ .. }
instead of the same output as the the first println! ?
2. If you remove the // below, why does it not compile ?
*/
use std::cell::RefCell;
use std::ops::DerefMut;
thread_local! {
static VEC: RefCell< Vec<f32> > = RefCell::new( vec![1.0, 2.0, 3.0] );
}
fn main() {
let v: RefCell< Vec<f32> > = RefCell::new( vec![1.0, 2.0] );
v.borrow_mut( ).deref_mut().push(3.0);
println!( "{:?}", v );
// VEC.borrow_mut( ).deref_mut().push(3.0);
println!( "{:?}", VEC );
}
When you use thread_local
, you do not actually get an item of the specified type, you get an item of type LocalKey<_>
. You have to use the methods of LocalKey
to reach the actual value.
To get &RefCell
from the LocalKey
, you have to use with()
.
VEC.with(|tl_vec| {
tl_vec.borrow_mut().push(3.0);
});
Or, there is also a combined version specifically for LocalKey<RefCell<_>>
:
VEC.with_borrow_mut(|tl_vec| {
tl_vec.push(3.0);
});
This callback pattern gives a couple of stronger guarantees than just returning a reference does:
- It guarantees that the reference cannot outlive this specific call, which is necessary for soundness here, because otherwise you could take a reference to a thread-local, send it to another thread, wait for the thread to terminate, and end up with a dangling reference.
- It guarantees that
with()
can run cleanup code after the callback function finishes. This doesn’t actually matter here, but it is critical for other uses of this callback pattern likestd::thread::scope()
.
Because that's what LocalKey
’s Debug
implementation does. Why? I don’t know exactly. Perhaps there could be a problematic situation if the value is not yet initialized. You'll need to call with()
before printing.
2 Likes
The program below works for me. Thanks.
use std::cell::RefCell;
thread_local! {
static VEC: RefCell< Vec<f32> > = RefCell::new( vec![1.0, 2.0] );
}
fn main() {
let v: RefCell< Vec<f32> > = RefCell::new( vec![1.0, 2.0] );
v.borrow_mut( ).push(3.0);
println!( "{:?}", v.borrow() );
//
VEC.with( |v| v.borrow_mut().push(3.0) );
VEC.with( |v| println!( "{:?}", v.borrow() ) );
}
1 Like