为何拥有型 trait 对象的相等运算符会移动右操作数?
为什么
Box<dyn Trait>使用==会移动右操作数? 核心原因
当你为dyn MyTrait实现PartialEq后,Rust解析left == right(left/right为Box<dyn MyTrait>)时,会优先尝试将操作数解引用为dyn MyTrait,匹配你实现的PartialEq for dyn MyTrait。但由于dyn MyTrait是非 Sized(!Sized)类型,Rust无法直接对right进行「自动引用+解引用」(即生成&*right),反而会将整个Box<dyn MyTrait>移动,生成临时的trait对象后取引用传递给eq方法。这直接导致原right变量的所有权被转移,后续无法再使用。
而标准库为Box<T>实现的PartialEq<Box<U>>虽然理论上可用,但Rust的类型解析优先级会优先选择更「直接」的trait对象实现,而非经过Box包装层的实现。
为什么官方文档的自动引用规则不生效?
官方文档提到的「比较运算符会隐式获取操作数的共享借用」是针对Sized类型的常规场景。当涉及!Sized的trait对象时,Rust的自动引用机制会出现异常:!Sized类型无法直接作为值存储或传递,只能通过引用,但解析逻辑错误地选择了移动整个智能指针,而非借用后解引用为trait对象引用。
有效解决方案
你找到的几种方案都能解决问题,这里整理各方案的适用场景:
- 比较trait对象引用:
&*left == &*right
明确指定借用trait对象,完全避免移动,适用于所有场景(包括assert_eq!)。 - 比较所有者引用:
&left == &right
利用标准库Box<T>的PartialEq实现,内部自动解引用到trait对象比较,无移动,适合assert_eq!。 - 解引用后比较:
*left == *right
直接比较trait对象,Rust会自动为两者添加引用,写法简洁且无移动。 - 显式调用
eq方法:left.eq(&right)
明确调用Box<T>的eq方法,无移动,但无法直接用于assert_eq!。
内容的提问来源于stack exchange,提问作者Jayonas
相关产品推荐
相关产品推荐

