Rust编译错误:boxed trait对象大小编译期未知,求代码修改方案
Rust Trait对象编译错误:dyn MyTrait大小无法确定的解决办法
问题代码
trait MyTrait { fn foo(&self); } struct A {} impl MyTrait for A { fn foo(&self) { println!("A"); } } struct B {} impl MyTrait for B{ fn foo(&self) { println!("B"); } } enum MyEnum { A, B, } fn create_object(my_enum: MyEnum) -> Box<dyn MyTrait> { let boxed_value: Box<dyn MyTrait> = match my_enum { MyEnum::A => Box::new(A{}), MyEnum::B => Box::new(B{}), }; boxed_value } struct C<Allocator> where Allocator: MyTrait + ?Sized { a: Box<Allocator>, } impl<Allocator> C<Allocator> where Allocator: MyTrait { pub fn new(a: Box<Allocator>) -> Self { Self {a: a} } } fn main() { let boxed_value = create_object(MyEnum::A); C::new(boxed_value); }
编译错误信息
编译 playground v0.0.1 (/playground) error[E0277]: 类型`dyn MyTrait`的值大小在编译期无法确定 --> src/main.rs:49:12 | 49 | C::new(boxed_value); | ------ ^^^^^^^^^^^ 编译期无法确定大小 | | | 此调用引入的约束要求 | = help: trait `Sized`未为`dyn MyTrait`实现 note: `C::<Allocator>::new`中的约束要求 --> src/main.rs:39:6 | 39 | impl<Allocator> C<Allocator> | ^^^^^^^^^ 此约束在`C::<Allocator>::new`中要求 40 | where Allocator: MyTrait { 41 | pub fn new(a: Box<Allocator>) -> Self { | --- 此关联函数中的约束要求 更多错误信息请尝试`rustc --explain E0277`。 error: 无法编译playground(bin "playground"),因之前的错误
错误原因
你说的没错,Box<dyn MyTrait>本身是固定大小的(它本质是一个胖指针,占两个机器字长),但问题出在C::new的泛型约束上:
Rust的泛型参数默认会自动加上Sized约束,也就是要求类型在编译期大小确定。你的C结构体定义里虽然给Allocator加了+ ?Sized(允许它是大小不确定的类型),但impl块里的Allocator没有这个标记,所以new方法默认要求Allocator必须是Sized类型。
当你传入Box<dyn MyTrait>时,泛型参数Allocator会被推断为dyn MyTrait,而dyn MyTrait是大小不确定的(!Sized),不符合impl块的默认约束,于是报错。
解决办法
有两种简单的修改方式:
方法一:给impl块的泛型参数加上?Sized约束
修改C的impl块,让Allocator允许是大小不确定的类型:
impl<Allocator: ?Sized> C<Allocator> where Allocator: MyTrait { pub fn new(a: Box<Allocator>) -> Self { Self { a } } }
方法二:调用时显式指定类型参数
在调用C::new时,直接指定Allocator为dyn MyTrait,跳过自动推断:
C::<dyn MyTrait>::new(boxed_value);
推荐用第一种方法,这样C的new方法可以兼容所有符合MyTrait的类型,不管是Sized还是!Sized。
完整可编译代码
trait MyTrait { fn foo(&self); } struct A {} impl MyTrait for A { fn foo(&self) { println!("A"); } } struct B {} impl MyTrait for B{ fn foo(&self) { println!("B"); } } enum MyEnum { A, B, } fn create_object(my_enum: MyEnum) -> Box<dyn MyTrait> { let boxed_value: Box<dyn MyTrait> = match my_enum { MyEnum::A => Box::new(A{}), MyEnum::B => Box::new(B{}), }; boxed_value } struct C<Allocator> where Allocator: MyTrait + ?Sized { a: Box<Allocator>, } impl<Allocator: ?Sized> C<Allocator> where Allocator: MyTrait { pub fn new(a: Box<Allocator>) -> Self { Self { a } } } fn main() { let boxed_value = create_object(MyEnum::A); C::new(boxed_value); }
内容的提问来源于stack exchange,提问作者JACK M
相关产品推荐
相关产品推荐

