Rust返回dyn trait对象的方法赋值变量后返回编译失败问题
根本原因
这个编译行为差异来自Rust类型推断与trait对象隐式转换的生效规则,两种写法在编译器的处理逻辑里确实存在区别:
- 当你直接将
Parent { child: Box::new(Daughter{}) }作为match分支的最后一个表达式返回时,编译器在解析该表达式时就已经知道它的目标类型必须匹配函数返回值Parent<dyn IsAChild>,因此构造值时会直接将类型推断为目标类型,自动完成Box<Daughter>到Box<dyn IsAChild>的trait对象转换。你写的带打印逻辑的compiles_too函数能编译也是同理:只要值是块的尾表达式直接作为返回值,编译器就会结合上下文目标类型提前做推断转换。 - 当你先把构造出的
Parent实例绑定到局部变量parent时,let语句的变量类型会在绑定行独立完成推断,不会提前感知后续这个变量要被作为Parent<dyn IsAChild>返回。此时let parent = Parent { child: Box::new(Daughter {}) };会被编译器直接推断为具体类型Parent<Daughter>,等后续返回parent时,Rust不会在变量返回的位置自动对具体结构体做动态大小类型(DST)的trait对象强转,因此抛出类型不匹配错误。
修复方案
如果确实需要先赋值给变量再返回,只需要在let绑定时显式标注变量类型,告知编译器提前做类型转换即可:
fn compiles_fixed() -> Parent<dyn IsAChild> { return match rand::thread_rng().gen_bool(1.0/2.0) { true => { let parent: Parent<dyn IsAChild> = Parent { child: Box::new(Daughter {}) }; parent }, false => { let parent: Parent<dyn IsAChild> = Parent { child: Box::new(Son {}) }; parent }, } }
规则补充:Rust的隐式trait对象转换仅会在「表达式所处上下文已经明确要求目标类型为
dyn Trait」时触发。局部变量绑定默认优先根据初始化表达式的具体类型确定类型,不会跨语句做隐式强转推断,这是编译器为了保证类型推断结果确定性做的设计,并非编译bug。
内容的提问来源于stack exchange,提问作者Dag Sondre Hansen
相关产品推荐
相关产品推荐

