对特征执行 Eq 检查
Enforce Eq check on trait
假设有以下对象:
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,所以我在函数上保留了类型保护检查。这里发生了什么?
我们来看看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
实现,如果两个特征对象不是同一具体类型,则返回 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)
}
}
请注意,此示例依赖于 Any.get_type_id
的不稳定功能 core
,因此仅适用于夜间;这可以通过将 Any
特征的定义复制到 C
的新超特征中来解决,也可以通过 mopafying the C
trait.
来简化
假设有以下对象:
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,所以我在函数上保留了类型保护检查。这里发生了什么?
我们来看看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
实现,如果两个特征对象不是同一具体类型,则返回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) } }
请注意,此示例依赖于
Any.get_type_id
的不稳定功能core
,因此仅适用于夜间;这可以通过将Any
特征的定义复制到C
的新超特征中来解决,也可以通过 mopafying theC
trait. 来简化