编者注:此代码示例来自1.0之前的Rust版本,并且在语法上不是有效的Rust 1.0代码。此代码的更新版本会产生不同的错误,但答案仍然包含有价值的信息。
在以下情况下,我们似乎无法测试相等性。为什么是这样?有解决方法吗? (我正在使用Rust 0.11)。
trait A: PartialEq {}
#[deriving(PartialEq)]
enum T {Ta, Tb}
impl A for T {}
fn main() {
assert!(Ta == Ta);
assert!(Ta != Tb);
assert!(some_fn(&Ta, &Ta));
assert!(!some_fn(&Ta, &Tb));
}
fn some_fn(an_a: &A, another_a: &A) -> bool {
an_a == another_a
// ERROR ^~~~~~~~~~~~ binary operation `==` cannot be applied to type `&A`
}
fn another_fn(an_a: &A + PartialEq, another_a: &A + PartialEq) -> bool {
// ERROR: ^~~~~~~~~ only the builtin traits can be used as closure or object bounds
an_a == another_a
}
答案 0 :(得分:11)
以下是PartialEq
特征的定义:
pub trait PartialEq<Rhs = Self>
where
Rhs: ?Sized,
{
fn eq(&self, other: &Rhs) -> bool;
fn ne(&self, other: &Rhs) -> bool { ... }
}
请注意Self
参数类型。这意味着eq()
和ne()
方法接受与实现者相同类型的参数。例如:
impl PartialEq for i32 {
fn eq(&self, other: &i32) -> bool { ... }
}
impl PartialEq for String {
fn eq(&self, other: &String) -> bool { ... }
}
请注意other
的类型如何更改以反映为PartialEq
实施的类型。
这就是问题所在。在特征对象中,实际类型已擦除并且在运行时不可用。这意味着不可能从特征对象获得对具体类型的引用;特别是,您的示例中不能从&A
转到&T
。
这意味着无法调用在特征对象上接受或返回Self
类型的方法。实际上,这些方法总是需要具体类型,但是如果你只有一个特征对象,那么没有具体类型,并且这种方法无法在任何方法中起作用明智的方式。
答案 1 :(得分:5)
使用help from Vladimir Matveev,我想出了如何使用Any
将我的特征向下转换为具体类型并测试结果值是否相等:
// `Any` allows us to do dynamic typecasting.
use std::any::Any;
trait A {
// An &Any can be cast to a reference to a concrete type.
fn as_any(&self) -> &Any;
// Perform the test.
fn equals_a(&self, &A) -> bool;
}
#[derive(Debug, PartialEq)]
enum T {
Ta,
Tb,
}
// Implement A for all 'static types implementing PartialEq.
impl<S: 'static + PartialEq> A for S {
fn as_any(&self) -> &Any {
self
}
fn equals_a(&self, other: &A) -> bool {
// Do a type-safe casting. If the types are different,
// return false, otherwise test the values for equality.
other
.as_any()
.downcast_ref::<S>()
.map_or(false, |a| self == a)
}
}
fn main() {
assert_eq!(T::Ta, T::Ta);
assert_ne!(T::Ta, T::Tb);
assert!(some_fn(&T::Ta, &T::Ta));
assert!(!some_fn(&T::Ta, &T::Tb));
}
fn some_fn(an_a: &A, another_a: &A) -> bool {
// It works!
an_a.equals_a(another_a)
}
答案 2 :(得分:3)
在某些特质对象的情况下,您希望根据通过特征暴露的某些属性来比较它们。您可以通过在特征类型本身上实现方法来实现这一目的:
trait A {
fn id(&self) -> i32;
}
impl<'a> PartialEq for A + 'a {
fn eq(&self, other: &Self) -> bool {
self.id() == other.id()
}
}
impl<'a> Eq for A + 'a {}
fn some_fn(an_a: &A, another_a: &A) -> bool {
an_a == another_a
}
这并不能直接解决原来需要委托给基础类型的PartialEq
实现的案例,但是你可以将Creating a Pandas DataFrame with a numpy array containing multiple types组合起来:
impl<'a> PartialEq for A + 'a {
fn eq(&self, other: &Self) -> bool {
self.equals_a(other)
}
}