Consider the following Rust code:
#[derive(Debug, Clone, Copy)]
struct Struct;
trait Trait {}
impl Trait for Struct {}
fn f() {
// Why does this coerce to the target type (Result<Box<dyn Trait>, ()>)
let rbdt: Result<Box<dyn Trait>, ()> = Ok(Box::new(Struct));
// And this coerces to the target type...
let a = Box::new(Struct);
let rbdt: Result<Box<dyn Trait>, ()> = Ok(a);
// But this does not:
let a = Ok(Box::new(Struct));
let rbdt: Result<Box<dyn Trait>, ()> = a; // Error: mismatched types
}
Why do the first two assignments to rbdt work correctly, coercing the value into the target type (Result<Box<dyn Trait>, ()>), but the 3rd one does not? It seems to me that in all three cases the type of the RHS of the assignment is Result<Box<Struct>, ()>, so it's perplexing that some forms work while other cause a mismatched types error.
What are the rules governing when types containing trait objects can be assigned to? Are these documented anywhere?
The underlying principle here is that the compiler will happily coerce a Box<Struct> into a Box<dyn Trait> by silently inserting an as wherever it's needed. But it needs a place to actually be able to rewrite the code as, literally, boxed_struct as BoxedTrait.
In the first example, this is possible:
let rbdt: Result<Box<dyn Trait>, ()> = Ok(Box::new(Struct) as Box<dyn Trait>);
And in the second:
let a = Box::new(Struct);
let rbdt: Result<Box<dyn Trait>, ()> = Ok(a as Box<dyn Trait>);
But in the third, there is nowhere for a Box<Struct>-as-Box<Trait> coercion to go. By the time you try to assign to rbdt, the type of a has already been determined to be Result<Box<Struct>, ()>, and at this point it's too late to try re-inferring the type to be the more general Result<Box<Trait>, ()>. The following is not a box-to-box coercion, so it isn't allowed.
let rbdt: Result<Box<dyn Trait>, ()> = a as Result<Box<dyn Trait>, ()>;
Box<Struct>-as-Box<Trait> is fine; Type<Box<Struct>>-as-Type<Box<Trait>>, for any Type, is not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With