Reputation: 3396
In the following code:
trait Animal {}
struct Dog {}
impl Animal for Dog {}
fn main() {
// first two lines are OK as expected
let _animal1: Box<dyn Animal> = Box::new(Dog {});
let _animal2: Box<dyn Animal> = Box::new(Dog {}) as Box<dyn Animal>;
// next line is a compile error: cast to unsized type: `Dog` as `dyn Animal`
let _animal3: Box<dyn Animal> = Box::new(Dog {} as dyn Animal);
}
Why is it an error to cast Dog{}
to dyn Animal
?
For this example, compiler correctly infer the type and the cast is redundant. However for the general case, what should be used to provide type information to compiler instead of dyn Animal
.
To state the question in a different way: what is the type of object given to Box::new()
, if it is not dyn Animal
?
Upvotes: 5
Views: 11737
Reputation: 22501
My understanding is that every reference to an object (e.g. &T
, &mut T
, Box<T>
, Arc<T>
etc) can exist without knowing the size of an object (e.g. fulfilling the Sized
trait). Which is the case in your first two lines in the example.
However, in the third line, you briefly (before passing it into Box::new()
) cast it into dyn Animal
, which is not a reference, but instead an object.
Every object that exists in Rust needs to have a known size, because otherwise Rust wouldn't know how much space to allocate for it on the stack. This isn't an issue for references, because references have a constant size independent of the object they are referencing.
Consider this:
let dog = Dog{};
// Works
let _animal : &dyn Animal = &dog as &dyn Animal;
// Fails
let _animal : dyn Animal = dog as dyn Animal;
I think the error message is very explanatory:
error[E0620]: cast to unsized type: `Dog` as `dyn Animal`
--> src/main.rs:13:32
|
13 | let _animal : dyn Animal = dog as dyn Animal;
| ^^^^^^^^^^^^^^^^^
|
help: consider using a box or reference as appropriate
--> src/main.rs:13:32
|
13 | let _animal : dyn Animal = dog as dyn Animal;
| ^^^
For more information about this error, try `rustc --explain E0620`.
The second part of your question is 'what should I use to cast dog into an animal?'.
I'd answer with: It depends on whether or not you want to carry over ownership.
If you do not want to carry over ownership and instead keep the original object:
let dog = Dog{};
let animal: &dyn Animal = &dog;
Else, if you want to move ownership into the animal object:
let dog = Dog{};
let animal: Box<dyn Animal> = Box::new(dog);
Upvotes: 5
Reputation: 98358
As the compiler says, you cannot cast to a dyn
type, because it is unsized. That is, a value of type dyn T
cannot exist in the stack.
You can only use dyn
types behind a pointer-like construct, such as &dyn _
or Box<dyn _>
, because the additional level of indirection means that the dyn
object itself does not exist, it is only a construction of the type system.
Those handle the inner conversion automatically. As you noticed you don't event need an explicit cast, the coercion is implicit.
These pointer like types do the conversion via the magic CoerceUnsized
trait (still unstable).
Upvotes: 1