强制Eq检查特征

时间:2015-05-17 18:38:13

标签: rust

假设以下对象:

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,所以我在函数上留下了类型保护的检查。这里发生了什么?

1 个答案:

答案 0 :(得分:3)

让我们看一下Eq的相关定义:

pub trait Eq: PartialEq<Self> {
    …
}

pub trait PartialEq<Rhs: ?Sized = Self> {
    fn eq(&self, other: &Rhs) -> bool;
    …
}

现在考虑MyStruct<Box<C>>:它想要实现的类型EqBox<C>,一个盒装的特征对象。要实施EqBox<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实现PartialEqBox<C>会这样做,所以我们讨论的实现应该放在未装箱的特征对象上,而不是放在盒装的特征对象上。 )

然而,很多时候,是一个明显而简单的实现。您可以采取一些方法:

  1. 将对象(可能是昂贵的,虽然理想地便宜)转换为某种基本类型,例如然后可以比较String;

  2. 放弃;

  3. 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进行简化。