我有一个特点,我为dyn Trait
实现了PartialEq
(和Eq
). 当我在Box<dyn Trait>
、Rc<dyn Trait>
或Arc<dyn Trait>
上使用相等运算符时,会导致右操作数为moved而不是borrow . 为什么? 除其他事项外,这防止直接在这些值上使用assert_eq!
.
docs for comparison operators人说:
与上面的算术和逻辑运算符不同,这些运算符隐式地接受操作数的共享borrow ,在表达式上下文中计算它们:
a == b;
// is equivalent to
::std::cmp::PartialEq::eq(&a, &b);
这意味着操作数不必移出.
我不明白为什么在这种情况下右操作数最终被移动. 在eq
方法中,正确的操作数不应该以&Box<dyn Trait>
(即借位)结束吗?
转载:(Playground)
use std::{
fmt,
rc::Rc,
sync::Arc,
};
trait MyTrait : fmt::Debug {
fn get_val(&self) -> u32;
}
#[derive(Clone, Debug)]
struct MyStruct {
val: u32,
}
impl MyTrait for MyStruct {
fn get_val(&self) -> u32 {
self.val
}
}
impl PartialEq for dyn MyTrait {
fn eq(&self, other: &Self) -> bool {
self.get_val() == other.get_val()
}
}
impl Eq for dyn MyTrait {}
fn main() {
// same error if you change `Box` to `Rc` or `Arc`
let left: Box<dyn MyTrait> = Box::new(MyStruct { val: 0 });
let right: Box<dyn MyTrait> = Box::new(MyStruct { val: 42 });
// assert_eq!(left, right); // error: cannot move out of `*right_val` [...]
let _ = left == right; // moves `right`
let _ = right.get_val(); // error: use of moved value
}
我找到了一些相对简单的解决办法:
- 解释德苏加:
left.eq(&right)
(虽然对assert_eq!
没有帮助) - 比较trait对象(即deref/unwrapped the own):
*left == *right
- 比较所有者参考:
&left == &right
- 比较trait对象引用:
&*left == &*right
- 以
Option
:Some(left) == Some(right)
包装(有限的帮助,因为价值观仍然被移动—进入Option
s)
但是(a)需要他们有点不满意,(b)我仍然想知道为什么会发生这种情况.