如果我已经将它们添加到另一个impl块中,为什么我需要在impl块上添加特征边界?

时间:2018-04-05 13:14:22

标签: generics rust traits bounds

我有以下代码:

use std::ops::Div;
use std::ops::Mul;

#[derive(Debug)]
struct Foo<T> {
    bar: T,
}

impl<T> Foo<T>
where
    T: Div<Output = T> + Copy,
{
    fn new(bar: T) -> Foo<T> {
        let baz = Foo::baz(bar);
        Foo { bar: bar / baz }
    }
    fn baz(bar: T) -> T {
        unimplemented!();
    }
}

impl<T> Mul for Foo<T>
where
    T: Mul<Output = T>,
{
    type Output = Foo<T>;

    fn mul(self, other: Foo<T>) -> Foo<T> {
        Foo::new(self.bar * other.bar)
    }
}

然而,编译器抱怨:

error[E0277]: cannot divide `T` by `T`
  --> src/main.rs:29:9
   |
29 |         Foo::new(self.bar * other.bar)
   |         ^^^^^^^^ no implementation for `T / T`
   |
   = help: the trait `std::ops::Div` is not implemented for `T`
   = help: consider adding a `where T: std::ops::Div` bound
note: required by `<Foo<T>>::new`
  --> src/main.rs:13:5
   |
13 |     fn new(bar: T) -> Foo<T> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
  --> src/main.rs:29:9
   |
29 |         Foo::new(self.bar * other.bar)
   |         ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
   |
   = help: consider adding a `where T: std::marker::Copy` bound
note: required by `<Foo<T>>::new`
  --> src/main.rs:13:5
   |
13 |     fn new(bar: T) -> Foo<T> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^

这可以通过以下修改来解决:

impl<T> Mul for Foo<T>
where
    T: Mul<Output = T> + Div<Output = T> + Copy,

为什么我需要将Div<Output = T>Copy添加到Mul for Foo<T>?由于:

Foo<T>不应满足范围
impl<T> Foo<T>
where
    T: Div<Output = T> + Copy,

1 个答案:

答案 0 :(得分:4)

每个impl块彼此完全不同,包括它们的特征边界 - 一个impl块具有约束的事实对其他块没有任何意义。

在这种情况下,特征impl的{​​{1}}块并不真正需要 Mul特征,因为它可以构建{{1}直接:

Div

这只是因为您选择调用Foo(具有impl<T> Mul for Foo<T> where T: Mul<Output = T>, { type Output = Foo<T>; fn mul(self, other: Foo<T>) -> Foo<T> { Foo { bar: self.bar * other.bar } } } Foo::new要求),Div的原始版本无法编译。这在概念上与这个普通函数相同,它也不需要CopyMul

Copy

请注意,我说过“Div阻止”,而非“固有fn x<T>(a: T) -> Foo<T> { Foo::new(a) } 阻止”或“特征impl阻止”。您可以拥有多个具有不同边界的固有impl块:

impl

这允许类型具有仅在满足某些条件时才适用的函数。

另见: