简体   繁体   中英

Coercing Arc<Mutex<Option<Box<MyStruct>>>>> to Arc<Mutex<Option<Box<dyn Trait>>>>> won't work

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>>>>`

Playground

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?

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 };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM