在下面的代码中:
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);
}
为什么将 Dog{}
转换为 dyn Animal
会出错?
对于此示例,编译器正确推断类型并且强制转换是多余的。然而,对于一般情况,应该使用什么来向编译器提供类型信息,而不是 dyn Animal
。
用不同的方式陈述问题:如果不是 dyn Animal
,则赋予 Box::new()
的对象类型是什么?
最佳答案
我的理解是,对对象的每个引用(例如 &T
、 &mut T
、 Box<T>
、 Arc<T>
等)都可以在不知道对象大小的情况下存在(例如满足Sized
特征)。示例中的前两行就是这种情况。
但是,在第三行中,您短暂地(在将其传递到 Box::new()
之前)将其转换为 dyn Animal
,它不是引用,而是一个对象。
Rust 中存在的每个对象都需要有一个已知的大小,否则 Rust 将不知道在堆栈上为其分配多少空间。这对于引用来说不是问题,因为引用具有独立于它们所引用的对象的恒定大小。
考虑一下:
let dog = Dog{};
// Works
let _animal : &dyn Animal = &dog as &dyn Animal;
// Fails
let _animal : dyn Animal = dog as dyn Animal;
我认为错误消息非常有解释性:
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`.
你问题的第二部分是“我应该用什么来把狗变成动物?”。
我的回答是:这取决于您是否想继承所有权。
如果您不想想要继承所有权并保留原始对象:
let dog = Dog{};
let animal: &dyn Animal = &dog;
否则,如果您想将所有权转移到动物对象中:
let dog = Dog{};
let animal: Box<dyn Animal> = Box::new(dog);
关于rust - 创建 Box<dyn Trait> 时如何转换为 dyn Trait,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72168734/