假设以下对象:
pub struct MyStruct<T>{
items: Vec<T>
}
pub impl<T> MyStruct<T> {
pub fn new() -> MyStruct {
MyStruct{ items::new(); }
}
pub fn add(&mut self, item: T) where T : Eq {
self.items.push(item);
}
}
pub trait C {}
pub struct Another {
mystruct: MyStruct<Box<C>>
}
pub impl Another {
pub fn exec<C>(&mut self, c: C) where C: Eq + C {
self.mystruct.add(c);
}
}
在exec上我强制执行C也是Eq,但我收到以下错误:
error: the trait `core::cmp::Eq` is not implemented for the type `C`
我不得不做
pub impl<T> MyStruct<T>
而不是
pub impl<T : Eq> MyStruct<T>
因为C是一个特性,所以当使用MyStruct :: new时我不能强制执行Eq,所以我在函数上留下了类型保护的检查。这里发生了什么?
答案 0 :(得分:3)
让我们看一下Eq
的相关定义:
pub trait Eq: PartialEq<Self> {
…
}
pub trait PartialEq<Rhs: ?Sized = Self> {
fn eq(&self, other: &Rhs) -> bool;
…
}
现在考虑MyStruct<Box<C>>
:它想要实现的类型Eq
是Box<C>
,一个盒装的特征对象。要实施Eq
,Box<C>
必须首先实施PartialEq<Box<C>>
,如下所示:
impl PartialEq for Box<C> {
fn eq(&self, other: &Box<C>) -> bool;
}
impl Eq for Box<C> { }
也就是说,您必须能够将任意Box<C>
与任意其他Box<C>
进行比较。您要比较的盒装特征对象可以是不同的具体类型,这里。因此,您需要手动编写此实现。在这种情况下,您通常希望特征包含一些将对象形式标准化为具体可比类型的方法;某些类型这是显而易见的;如果AsRef<T>
要添加PartialEq
实现,则添加的实现将非常明显:
impl<T: PartialEq> PartialEq for AsRef<T> {
fn eq(&self, other: &AsRef<T>) -> bool {
self.as_ref() == other.as_ref()
}
}
(另请注意,如果C
实现PartialEq
,Box<C>
会这样做,所以我们讨论的实现应该放在未装箱的特征对象上,而不是放在盒装的特征对象上。 )
然而,很多时候,不是一个明显而简单的实现。您可以采取一些方法:
将对象(可能是昂贵的,虽然理想地便宜)转换为某种基本类型,例如然后可以比较String
;
放弃;
将C
约束到'static
类型并使用一些花哨的Any
魔术来使其使用基类型的PartialEq
实现,返回{{1如果两个特征对象不是同一个具体类型。这个是非常有用的,所以我会给它一些代码:
false
请注意,此示例取决于#![feature(core)]
use std::any::{Any, TypeId};
use std::mem;
fn main() { }
trait PartialEqFromC {
fn eq_c(&self, other: &C) -> bool;
}
impl<T: PartialEq + Any + C> PartialEqFromC for T {
fn eq_c(&self, other: &C) -> bool {
if other.get_type_id() == TypeId::of::<Self>() {
self == unsafe { *mem::transmute::<&&C, &&Self>(&other) }
} else {
false
}
}
}
trait C: Any + PartialEqFromC {
}
impl PartialEq for C {
fn eq(&self, other: &C) -> bool {
self.eq_c(other)
}
}
的不稳定功能core
,因此仅限于夜间;这可以通过将Any.get_type_id
特征中的定义复制到Any
的新超级列表中来解决,也可以通过mopafying the C
trait进行简化。