Давайте посмотрим на соответствующие определения для 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>
делает, поэтому такие реализации, как мы обсуждали, должны идти на unboxed trait object, а не на объект с боксами.)
Довольно часто, однако, есть не очевидная и простая реализация. Есть несколько подходов можно принять:
Преобразование объектов (потенциально дорого, хотя в идеале дешево) в какой-то базовый тип, например, a String
, который затем можно сравнить;
Отказ;
Constrain C
к 'static
типы и использовать некоторые фантазии Any
магию, чтобы сделать так, что он использует PartialEq
реализацию базового типа, возвращая false
, если два объекта Trait не одного и того же конкретного типа.Это одна довольно полезная, так что я дам код для него:
#![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
в новый супертрайт C
, а также может быть упрощено на mopafying the C
trait.
Ваш примерный код не воспроизводит ошибку, о которой вы заявляете (это не [MCVE] (http://stackoverflow.com/help/mcve)). Если это случится, вы можете получить больше ответов. Кроме того, стиль Rust - это 4-х сторонние отступы. – Shepmaster
Поскольку у Криса Моргана есть ответ, я также укажу, что ваша реализация 'add' имеет параметр типа' T', который затеняет параметр типа struct, а в вашей реализации 'exec' параметр типа 'C' затеняет черту' C', что приводит к потенциально запутанному сообщению об ошибке. – Shepmaster
@Shepmaster, спасибо за отзыв. Фактически, у add не было шаблона, это было вызвано ошибкой копирования/вставки и переименованием класса (компиляция этого приводит к ошибке при затенении, как вы упомянули). В следующий раз я попытаюсь создать MCVE, чтобы лучше воспроизвести проблему. – scooterman