有没有办法在另一个特征之上实现特征?

joc*_*ull 7 traits rust

我想创建一个基本特征,将实现其他运营商的特征(Add,Subtract,Multiply,Divide,等...)我.

这无法编译,它看起来像一个发布Sized,但即使Measurement设置为要求Sized它不起作用.这甚至可能吗?

use std::ops::Add;

#[derive(Copy, Clone, Debug)]
struct Unit {
    value: f64,
}

impl Unit {
    fn new(value: f64) -> Unit {
        Unit { value: value }
    }
}

trait Measurement: Sized {
    fn get_value(&self) -> f64;
    fn from_value(value: f64) -> Self;
}

impl Measurement for Unit {
    fn get_value(&self) -> f64 {
        self.value
    }
    fn from_value(value: f64) -> Self {
        Unit::new(value)
    }
}

// This explicit implementation works
/*
impl Add for Unit {
    type Output = Unit;

    fn add(self, rhs: Unit) -> Unit {
        let a = self.get_value();
        let b = rhs.get_value();
        Unit::from_value(a + b)
    }
}
*/

// This trait implementation does not
impl Add for Measurement {
    type Output = Self;

    fn add(self, rhs: Self) -> Self {
        let a = self.get_value();
        let b = rhs.get_value();
        Self::from_value(a + b)
    }
}

fn main() {
    let a = Unit::new(1.5);
    let b = Unit::new(2.0);
    let c = a + b;

    println!("{}", c.get_value());
}
Run Code Online (Sandbox Code Playgroud)

(游乐场)

error[E0277]: the trait bound `Measurement + 'static: std::marker::Sized` is not satisfied
  --> src/main.rs:42:6
   |
42 | impl Add for Measurement {
   |      ^^^ `Measurement + 'static` does not have a constant size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `Measurement + 'static`

error[E0038]: the trait `Measurement` cannot be made into an object
  --> src/main.rs:42:6
   |
42 | impl Add for Measurement {
   |      ^^^ the trait `Measurement` cannot be made into an object
   |
   = note: the trait cannot require that `Self : Sized`

error[E0038]: the trait `Measurement` cannot be made into an object
  --> src/main.rs:43:5
   |
43 |     type Output = Self;
   |     ^^^^^^^^^^^^^^^^^^^ the trait `Measurement` cannot be made into an object
   |
   = note: the trait cannot require that `Self : Sized`

error[E0038]: the trait `Measurement` cannot be made into an object
  --> src/main.rs:45:5
   |
45 |     fn add(self, rhs: Self) -> Self {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Measurement` cannot be made into an object
   |
   = note: the trait cannot require that `Self : Sized`
Run Code Online (Sandbox Code Playgroud)

mdu*_*dup 7

问题不在于大小.您正在寻找的语法是:

impl<T: Measurement> Add for T { ... }
Run Code Online (Sandbox Code Playgroud)

代替:

impl Add for Measurement { ... }
Run Code Online (Sandbox Code Playgroud)

因为for必须是对象的右侧而不是特征,所以限制为特征的类型参数(即T必需的Measurement)是有效的.


现在你的代码仍然无法编译.您将获得以下内容:

error:type参数T必须用作某些本地类型的类型参数(例如MyStruct<T>); 只有当前包中定义的特征才能为类型参数实现[E0210]

这里的问题完全不同.我不确定它是否与这个问题有关,但我仍然会解释发生了什么.当你写一个IMPL Add任何T这是Measurement,你打开一个类型就已经实现的可能性Add就其本身而言,也将实现Measurement在其他地方.试想一下,如果你想实现Measurementu8(这是愚蠢的,但可能):这应该IMPL选择生锈了Add?最初的stdimpl还是你的Measurementimpl?(关于这个问题的深入讨论)

现在Rust显然禁止impl如果它不是至少1)你自己的特性或2)你自己的类型("拥有"正式意味着,在你正在写你的impl的箱子里).这就是为什么你可以写impl Add for Unit:因为你拥有Unit.

最简单的解决方案是为您计划制作的每种类型单独放弃并实施Add Unit.说你的箱子定义InchesCentimeter,每个人将有自己的AddIMPL.如果代码侮辱性地相似,并且你觉得你破坏了DRY,那就利用.下面是该怎么std箱子做它:

macro_rules! add_impl {
    ($($t:ty)*) => ($(
        #[stable(feature = "rust1", since = "1.0.0")]
        impl Add for $t {
            type Output = $t;

            #[inline]
            fn add(self, other: $t) -> $t { self + other }
        }

        forward_ref_binop! { impl Add, add for $t, $t }
    )*)
}
Run Code Online (Sandbox Code Playgroud)