use std::sync::{Arc, Mutex};
trait B{}
struct A{
}
impl B for A{}
fn main() {
let a = A{};
let b: Arc<Mutex<dyn B>> = Arc::new(Mutex::new(a));
//Can I lock `b` and change the inner `a`?
}
I wanted something like this:
b.lock().unwrap().reset(A{});
I though of doing
let b: Arc<Mutex<Option<dyn B>>> = Arc::new(Mutex::new(a));
error[E0277]: the size for values of type `dyn B` cannot be known at compilation time
--> src/main.rs:13:12
|
13 | let b: Arc<Mutex<Option<dyn B>>> = Arc::new(Mutex::new(Some(a)));
| ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn B`
but it won't work, it says `B` is not `Sized`.
Why there's no easy way to do this?
I could explain why I want this but I think the question would be too long. But basically I want to be able to call an Arc<Mutex<dyn B>> even if its inner object gets changed.
While A has a trait impl for B, in order to make a trait object i.e. dyn B, that value is what's called a Dynamically Sized Type (DST) and as such must be behind some kind of pointer. So b.lock().unwrap().reset(A{}); should become b.lock().unwrap().reset(Box::new(A{}));
Even after this change, where exactly is the .reset() method supposed to be defined? Mutex has no such method, and neither do MutexGuard or the trait B.
use std::sync::{Arc, Mutex};
trait B{
fn do_something(&self);
}
struct A{
message: String
}
impl A{
}
impl B for A{
fn do_something(&self){
println!("{}", self.message);
}
}
fn main() {
let a = A{
message: "message1".to_string()
};
let b: Arc<Mutex<Option<Box<dyn B + Send + Sync>>>> = Arc::new(Mutex::new(Some(Box::new(a))));
let b_clone = b.clone();
std::thread::spawn(move ||{
loop {
let bb = b_clone.lock().unwrap();
if bb.as_ref().is_some() {
bb.as_ref().unwrap().do_something();
}
std::thread::sleep(std::time::Duration::from_secs(1));
}
});
std::thread::sleep(std::time::Duration::from_secs(2));
let aa = A{
message: "message2".to_string()
};
*b.lock().unwrap() = Some(Box::new(aa));
std::thread::sleep(std::time::Duration::from_secs(1000));
println!("end");
}
it works. I can substitute the inside Arc on the fly, and the loop will just keep working on the replaced one without noticing, which was the goal. Do you think this is the simplest way of doing this? I think : Arc<Mutex<Option<Box<dyn B + Send + Sync>>>> is a too heavy signature
Indeed. I forgot to mention that sometimes the object needs to create the object in advance so I added the Option so it can create one that 'points' to nothing. Later a dyn B can be setted.
Box works fine for me but I was wondering, would it be possible to do without dynamic allocation? Maybe
Arc<Mutex<Option<Arc<dyn B + Send + Sync>>>>
but of couse without Arc in the dyn part because Arc has no interior mutability.