Can you please explain the reason for this to me
use std::future::Future;
pub struct A{}
pub struct B<'a>{
pub i: &'a A,
}
impl<'a> B<'a>{
fn new(x:&'a A)->Self{
Self{i:x}
}
async fn print_any(&self){
println!("xxxxxxxxxxxxxxxxxxxxx")
}
}
fn main() {
let aa = A{};
let bb = B::new(&aa);
futures::future::join3(
tokio::spawn(bb.print_any()),
tokio::spawn(bb.print_any()),
tokio::spawn(bb.print_any())
);
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7556ae4ab612ca6a99e51ec4c736425f
error[E0597]: `aa` does not live long enough
--> src/main.rs:23:21
|
23 | let bb = B::new(&aa);
| -------^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `aa` is borrowed for `'static`
...
32 | }
| - `aa` dropped here while still borrowed
and how to fix that?
Thread safety requires that a thread can't borrow a value for less than static.
You could use Arc to pass thread safe pointers to each thread.
Also, you must use the tokio main() if you want to be able to use the tokio runtime.
I couldn't find a solution to use the join3 method, because the expression makes impossible to create 3 Arc references without having to borrow 3 times the same value inside the threads.
So I propose this solution
use std::sync::Arc;
use std::io;
pub struct A{}
pub struct B {
pub i: Arc<A>,
}
impl B {
fn new(x:Arc::<A>) -> Self {
Self{i:x}
}
async fn print_any(&self) {
println!("xxxxxxxxxxxxxxxxxxxxx")
}
}
#[tokio::main]
async fn main()-> io::Result<()> {
let aa = Arc::new(A{});
let bb = Arc::new(B::new(aa));
for _ in 0..3 {
let b = Arc::clone(&bb);
tokio::spawn( async move {
b.print_any().await ;
});
}
Ok(())
}
Using Arc pointers removes the necessity of using explicit lifetime parameters.
Related
I want to simulate some natural process, so I have a Simulator, and a reactor like a NuclearReactor. The simulator will modify the reactor, and the reactor can reversely influance the simulator by modifying it. One important thing is that the NuclearReactor is wrapped from somewhere else, the solid_function must has a inmutable &self.
So after reading rust book of RefCell, I wrote something like these:
use std::borrow::BorrowMut;
use std::cell::RefCell;
use std::rc::{Rc, Weak};
pub struct Simulator {
nr: NuclearReactor,
data: Vec<f64>,
}
impl Simulator {
pub fn on_nuclear_data(&mut self, x: i64) {
// modify self
}
pub fn run_simulation(&mut self) {}
}
pub struct NuclearReactor {
simulator: Option<Weak<RefCell<Simulator>>>,
}
impl NuclearReactor {
pub fn solid_function(&self, x: i64) {
/*
this function `&self` is solid, so I have to use a RefCell to wrap Simulator
*/
}
pub fn write_simulator(&self) {
/*
none of the two following snippets will work
*/
/* snippet1: compiler says:
error[E0507]: cannot move out of an `Rc`
--> src/main.rs:87:17
|
87 | let t = *self.simulator.unwrap().upgrade().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| move occurs because value has type `RefCell<Simulator>`, which does not implement the `Copy` trait
| help: consider borrowing here: `&*self.simulator.unwrap().upgrade().unwrap()`
*/
let t = *self.simulator.unwrap().upgrade().unwrap();
t.borrow_mut().on_nuclear_data(0);
/*
snippet2: compiler says:
error[E0599]: no method named `on_nuclear_data` found for mutable reference `&mut Rc<RefCell<Simulator>>` in the current scope
--> src/main.rs:101:65
|
101 | self.simulator.unwrap().upgrade().unwrap().borrow_mut().on_nuclear_data(0);
| ^^^^^^^^^^^^^^^ method not found in `&mut Rc<RefCell<Simulator>>`
*/
// self.simulator.unwrap().upgrade().unwrap().borrow_mut().on_nuclear_data(0);
}
}
pub fn main() {
let nr_ = NuclearReactor {
simulator: None
};
let mut sm_ = Rc::new(RefCell::new(Simulator {
nr: nr_,
data: vec![],
}));
(*sm_).borrow_mut().nr.simulator = Some(Rc::downgrade(&sm_));
}
But it won't compile. How should I solve it.
Oh... the compile hints me solved it. But it seems complicated. Can anyone explain that, or give a better pattern? I think the pattern is common.
let t = &*self.simulator.as_ref().unwrap().upgrade().unwrap();
t.borrow_mut().on_nuclear_data(0);
Actually it should be:
(*self.simulator.as_ref().unwrap().upgrade().unwrap()).borrow_mut().on_nuclear_data(0);
This is because &Option<T> cannot be unwrapped.
self.simulator, where self is a &Self, gets a &Option<Weak<RefCell<Simulator>>>.
Option<T>::unwrap consumes the self and return the inner value by 'move'.
Option<T>::as_ref converts &self into an Option<&T> safely so that you can unwrap into a &T.
This question already has an answer here:
Why is there a borrow of a moved value when calling a method that takes self by value with an argument that also calls a method?
(1 answer)
Closed last year.
The below rust code has compilation error.
struct Builder;
impl Builder {
pub fn add(&mut self, id: i32) -> i32 {
id + 1
}
}
fn main() {
let mut b = Builder;
b.add(b.add(10));
}
error[E0499]: cannot borrow `b` as mutable more than once at a time
--> examples/mutable_borrow_at_a_time.rs:10:11
|
10 | b.add(b.add(10));
| - --- ^ second mutable borrow occurs here
| | |
| | first borrow later used by call
| first mutable borrow occurs here
Unlike the question Cannot borrow `x` as mutable more than once at a time, add does not return any reference at all.
Unlike the question Borrow errors for multiple borrows, the return type is i32 which has 'static lifetime.
While the following code can be compiled without errors.
struct Builder;
impl Builder {
pub fn add(&mut self, id: i32) -> i32 {
id + 1
}
}
fn main() {
let mut b = Builder;
let x = b.add(10);
b.add(x);
}
Anyway it is cumbersome to create a dummy variable x every time for a compound expression.
First there will be a mutable borrow on the outer b.add(...) and then there will be an attempt to make a second mutable borrow on the inner b.add(). That is wonderfully explained & visualized by the compiler in the error message that you pasted:
| b.add(b.add(10));
| - --- ^ second mutable borrow occurs here
| | |
| | first borrow later used by call
| first mutable borrow occurs here
This limitation might be removed at some point, but for now, that's how it works.
And for your specific example, as Jmb mentioned, you don't need mut at all, so this will work just fine:
struct Builder;
impl Builder {
pub fn add(&self, id: i32) -> i32 {
id + 1
}
}
fn main() {
let b = Builder;
b.add(b.add(10));
}
It looks like you are attempting to use the builder pattern.
The difficulty stands in passing a &mut on the builder from call to call.
Each step in the chain should rather consume the previous state of the builder and emit a new state (like add() here).
Finally, the last step (build()) consumes the builder for the last time and emits instead the value we intended to build.
You might be worried about the performance cost of these multiple move/consume operations (instead of altering through a &mut), but when enabling optimizations, the compiler is able to look through these calls and can decide to do everything in place: a function only containing Builder::new().add(10).add(20).build() produces mov eax, 30 ret.
struct Builder {
id: i32,
}
impl Builder {
pub fn new() -> Self {
Builder { id: 0 }
}
pub fn add(
mut self,
incr: i32,
) -> Self {
self.id += incr;
self
}
pub fn build(self) -> i32 {
self.id
}
}
fn main() {
let id = Builder::new().add(10).add(20).build();
println!("id={:?}", id);
}
My question is the following:
Would it be possible to make a deferred initialization of an object and then borrow it as mutable for a 'static lifetime?
Some context
First of all, I am going to show an example of what I mean by deferred initialization. The deferred initialization model that I have come up with is to use the crate lazy_static with a standard library Mutex holding an Option<T>. Here there is an example of a deferred initialization.
use lazy_static::lazy_static;
use std::thread::JoinHandle;
use std::sync::Mutex;
pub struct DeferredStruct {
internal_field: u32,
}
impl DeferredStruct {
pub fn new(internal_field: u32) -> Self {
Self {
internal_field,
}
}
pub fn regular_function(&mut self) {
self.internal_field += 1;
println!("{}", self.internal_field);
}
}
lazy_static! {
static ref MY_DEFERRED: Mutex<Option<DeferredStruct>> = Mutex::new(None);
}
fn main() {
// Initial processing
// ...
// ...
// The value 10 would be obtained from a configuration file on runtime.
let deferred_struct = DeferredStruct::new(10);
let mut lock = MY_DEFERRED.lock().unwrap();
lock.replace(deferred_struct);
std::mem::drop(lock); // In this example we drop the lock to avoid a deadlock when calling another_function.
// More processing
// ...
// ...
let thread_handle = another_function();
thread_handle.join().unwrap();
}
// From another part of the program and possibly from another thread we
// lock MY_DEFERRED and call regular_funcion on it.
fn another_function() -> JoinHandle<()> {
std::thread::spawn(|| {
let mut lock = MY_DEFERRED.lock().unwrap();
if let Some(deferred) = lock.as_mut() {
deferred.regular_function();
}
})
}
You can execute the above code in Rust Playground and check that it prints 11 correctly.
Introducing a struct function that requires a static lifetime
Now, let's say I add a function inside DeferredStruct that will create a worker thread in order to execute some computations that will take a long time:
pub struct DeferredStruct {
internal_field: u32,
}
impl DeferredStruct {
pub fn new(internal_field: u32) -> Self {
Self {
internal_field,
}
}
pub fn regular_function(&mut self) {
self.internal_field += 1;
println!("{}", self.internal_field);
}
pub fn static_function(&'static mut self) {
std::thread::spawn(move || {
// Do something really long.
// Finally I make some changes on self
self.internal_field += 100;
});
}
}
In this case is required for &mut self to have a 'static lifetime:
error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement.
Due to this, the function will take a &'static mut self.
The problem comes when trying to borrow the DeferredStruct inside the Option in MY_DEFERRED as 'static and mut.
If I cannot borrow for 'static and mut then I cannot call deferred.static_function(). As the value will not live for long enough.
error[E0597]: `lock` does not live long enough
--> src/main.rs:57:33
|
57 | if let Some(deferred) = lock.as_mut() {
| ^^^^---------
| |
| borrowed value does not live long enough
| argument requires that `lock` is borrowed for `'static`
...
60 | })
| - `lock` dropped here while still borrowed
Here there is a minimal reproducible example in Rust Playground.
TL;DR
Is it possible to borrow an object created at runtime (not necessarily created at the immediate start of the program) inside a Mutex<Option<T>> as mutable and for a 'static lifetime?
Any help is appreciated.
I want to store a closure in struct that implements Clone, so i'm code this:
use std::rc::Rc;
type Closure = Box<dyn Fn() -> ()>;
#[derive(Clone)]
struct A {
closure: Option<Rc<Closure>>,
}
impl A {
pub fn new() -> A {
A { closure: None }
}
pub fn closure(&self) -> Option<Rc<Closure>> {
self.closure.clone()
}
pub fn set_closure(&mut self, closure: Closure) -> &mut Self {
self.closure = Some(Rc::new(closure));
self
}
}
fn main() {
let mut a: A = A::new();
a.set_closure(Box::new(|| -> () { println!("Works fine!") }));
(a.closure().unwrap())();
}
Now I want to test this code by borrowing a variable of current scope. It's important to keep a reference in main function, because i need to use it after.
I code this:
use std::cell::RefCell;
fn main() {
let mut a: A = A::new();
let value: Rc<RefCell<i8>> = Rc::new(RefCell::new(0));
println!("Value = {}", value.borrow());
a.set_closure(Box::new(|| -> () {
*value.borrow_mut() = 1;
}));
(a.closure().unwrap())();
println!("New value = {}", value.borrow());
}
But I get this error:
Compiling playground v0.0.1 (/playground)
error[E0597]: `value` does not live long enough
--> src/main.rs:34:38
|
34 | a.set_closure(Box::new(|| -> () { *value.borrow_mut() = 1; }));
| ---------------------^^^^^---------------------
| | | |
| | | borrowed value does not live long enough
| | value captured here
| cast requires that `value` is borrowed for `'static`
...
38 | }
| - `value` dropped here while still borrowed
Would anyone know what I need to do please.
Thank you for your reply in advance.
Rcs are shared by cloning, which increments their reference count. But you pass a reference to it to the closure, which is perhaps defeating the point of using an Rc in the first place. As the error says, the closure is holding a reference to value after value is dropped.
You probably intended to write something like this, which clones the Rc and moves the clone into the closure:
let cloned_value = value.clone();
a.set_closure(Box::new(move || *cloned_value.borrow_mut() = 1));
Or (my preference) avoiding introducing a new binding in the outer scope:
a.set_closure(Box::new({
let value = value.clone();
move || *value.borrow_mut() = 1
}));
Being new to rust I wanted to play with some data structures and ended up with something like a node type without payload.
use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::Drop;
#[derive(Debug)]
struct Container<'a> {
next : Option<&'a RefCell<Container<'a>>>,
}
impl<'a> Container<'a> {
fn new() -> Container<'a> {
Container { next: None }
}
fn set(&mut self, next: &'a RefCell<Container<'a>>) {
self.next = Some(next);
}
}
The goal was to have these nodes not own their neighbours, so std::rc::Rc was out of the question.
So I did some testing which went fine:
fn main() {
// items:
let cont_1 = RefCell::new(Container::new());
let cont_2 = RefCell::new(Container::new());
let b_1 = &cont_1;
let b_2 = &cont_2;
(*b_2).borrow_mut().set(b_1);
(*b_1).borrow_mut().set(b_2);
println!("{:?}", b_1.borrow());
}
Since I was playing around I then tried to implement the Drop trait on the Container type
impl<'a> Drop for Container<'a>{
fn drop(&mut self) {}
}
which results in two of (the other one for cont_2)
error[E0597]: `cont_1` does not live long enough
--> src/main.rs:11:15
|
11 | let b_1 = &cont_1;
| ^^^^^^^ borrowed value does not live long enough
...
18 | }
| -
| |
| `cont_1` dropped here while still borrowed
| borrow might be used here, when `cont_1` is dropped and runs the destructor for type `std::cell::RefCell<Container<'_>>`
Now, I believe, that Drop causes the deallocation to be at the end of scopes otherwise it would usually take place after the last use? But either way the complaint is about the value not living long enough... I have tried adding drop(...) in between, but failed. I guess I dont even understand how exactly the order of deallocation changed. I would expect that cont_1 would be deallocated last since it was initialized/declared first meaning that I don't really understand how it could still be borrowed.
What would happen if in your drop() implementation you use self.next.unwrap()...? Since one of your variables will necessarily be dropped before the other, the last one will have a dangling reference, and so undefined behavior. So you code is correct in not to compile.
IMO, the solution is to use some kind of reference counted pointers. If you do not want Rc, because they do not own the neighbors (it will create a reference loop and thus leak your objects), you can use Weak references. Something like this (playground):
use std::cell::RefCell;
use std::ops::Drop;
use std::rc::{Rc, Weak};
#[derive(Debug)]
struct Container {
next : Option<Weak<RefCell<Container>>>,
}
impl Container {
fn new() -> Container {
Container { next: None }
}
fn set(&mut self, next: &Rc<RefCell<Container>>) {
self.next = Some(Rc::downgrade(next));
}
}
impl Drop for Container{
fn drop(&mut self) {}
}
fn main() {
// items:
let cont_1 = Rc::new(RefCell::new(Container::new()));
let cont_2 = Rc::new(RefCell::new(Container::new()));
cont_1.borrow_mut().set(&cont_1);
cont_2.borrow_mut().set(&cont_2);
println!("{:?}", cont_1.borrow());
}