Reputation: 2148
I'm trying to store a dyn trait inside Arc<Mutex<Option<Box<>>>>>
, however for some reason it won't work
use std::sync::{Arc, Mutex};
trait A{}
struct B{}
impl A for B{}
struct H{
c: Arc<Mutex<Option<Box<dyn A>>>>
}
fn main() {
let c =
Arc::new(Mutex::new(Some(Box::new(B{}))));
H{
c: c
};
}
Error:
error[E0308]: mismatched types
--> src/main.rs:17:12
|
17 | c: c
| ^ expected trait object `dyn A`, found struct `B`
|
= note: expected struct `Arc<Mutex<Option<Box<(dyn A + 'static)>>>>`
found struct `Arc<Mutex<Option<Box<B>>>>`
It looks like it cannot store a dyn
as a Box<B>
, which is strange because this works:
fn main() {
let c: Arc<Mutex<Option<Box<dyn A>>>> =
Arc::new(Mutex::new(Some(Box::new(B{}))));
}
What's the difference?
Upvotes: 3
Views: 1055
Reputation: 43773
What's the difference?
There is a very special case for Box
and other standard library types that can contain dynamically-sized values like dyn A
.
let c = Arc::new(Mutex::new(Some(Box::new(B{}))));
H { c: c };
In this code, you have initialized the variable c
— with no type declaration — to a value whose type is inferred as Arc<Mutex<Option<Box<B>>>
, and then try to store it in a field of of type Arc<Mutex<Option<Box<dyn A>>>
. This cannot work, because the two types have different memory layouts.
let c: Arc<Mutex<Option<Box<dyn A>>>> =
Arc::new(Mutex::new(Some(Box::new(B{}))));
In this code, you have given c
a type declaration, as a consequence of which the need for dyn
is known at the point where it is constructed, which allows the coercion to happen soon enough, You can coerce a Box<B>
to a Box<dyn A>
, because Box
implements the special trait CoerceUnsized
. (The same mechanism applies to converting &B
to &dyn A
.) But, this does not apply to arbitrary types containing a Box<B>
— not even Option<Box<B>>
, let alone your more complex type.
You can give c
a type when you're constructing it:
let c: Arc<Mutex<Option<Box<dyn A>>>> = Arc::new(Mutex::new(Some(Box::new(B{}))));
H { c: c };
Or, slightly shorter but odder, you can annotate just the immediate container of the Box
with the type it needs:
let c = Arc::new(Mutex::new(Some::<Box<dyn A>>(Box::new(B{}))));
H { c: c };
Or you can write an explicit coercion with the as
operator:
let c = Arc::new(Mutex::new(Some(Box::new(B{}) as Box<dyn A>)));
H { c: c };
Upvotes: 3