rust - 我如何向编译器解释通用函数返回可用于减法的数据?

标签 rust

如果对通用结构使用通用实现,我会收到错误消息。我应该如何向编译器解释last 函数返回的数据可以用于减法运算?

use std::ops::Sub;

struct Container<A, B>(A, B);

trait Contains {
    type A;
    type B;

    fn contains(&self, &Self::A, &Self::B) -> bool;
    fn first(&self) -> Self::A;
    fn last(&self) -> Self::B;
}

impl<C: PartialEq, D: PartialEq + Sub> Contains for Container<C, D> {
    type A = C;
    type B = D;

    fn contains(&self, number_1: &Self::A, number_2: &Self::B) -> bool {
        (&self.0 == number_1) && (&self.1 == number_2)
    }
    fn first(&self) -> Self::A {
        self.0
    }
    fn last(&self) -> Self::B {
        self.1
    }
}

fn difference<C: Contains>(container: &C) -> i32 {
    container.last() - container.first()
}

fn main() {
    let number_1 = 3;
    let number_2 = 10;

    let container = Container(number_1, number_2);

    println!("Does container contain {} and {}: {}",
             &number_1,
             &number_2,
             container.contains(&number_1, &number_2));
    println!("First number: {}", container.first());
    println!("Last number: {}", container.last());

    println!("The difference is: {}", difference(&container));
}

我得到一个错误:

error[E0369]: binary operation `-` cannot be applied to type `<C as Contains>::B`
  --> src/main.rs:30:5
   |
30 |     container.last() - container.first()
   |     ^^^^^^^^^^^^^^^^
   |
   = note: an implementation of `std::ops::Sub` might be missing for `<C as Contains>::B`

最佳答案

这是一个有趣的俄罗斯方 block 类型:)

其他人可能能够权衡更好的方法来实现您正在尝试做的事情,但我至少可以解释为什么您的代码无法编译。

有四个问题:

  • 您对 difference 的实现在 Contains 的所有实现中都是通用的,因此仅对 Container 施加约束是不够的的类型 - 您还需要将它们放在特征本身上。

  • 因为您正试图减去 Self::A 类型的对象来自 Self::B 类型的对象,您需要在约束中指定 - 它默认为 Sub<Self> .

  • Rust 不会隐式转换 difference 的结果到i32 - 你要么需要对 difference 的返回值通用,或添加显式转换(这将涉及添加更多类型约束)。我做了前者,因为它似乎更符合您要实现的目标。

  • firstlast尝试移动 self.0 的所有权和 self.1在结构之外 - 你需要让他们返回借用(这将涉及终身恶作剧),或限制 Contains只允许 Copy类型。

完成这些更改后,您的代码将如下所示:

use std::ops::Sub;

struct Container<A, B>(A, B);

trait Contains {
    type A: Copy + PartialEq;
    type B: Copy + PartialEq + Sub<Self::A>;

    fn contains(&self, &Self::A, &Self::B) -> bool;
    fn first(&self) -> Self::A;
    fn last(&self) -> Self::B;
}

impl<C, D> Contains for Container<C, D>
where
    C: Copy + PartialEq,
    D: Copy + PartialEq + Sub<C>,
{
    type A = C;
    type B = D;

    fn contains(&self, number_1: &Self::A, number_2: &Self::B) -> bool {
        (&self.0 == number_1) && (&self.1 == number_2)
    }
    fn first(&self) -> Self::A {
        self.0
    }
    fn last(&self) -> Self::B {
        self.1
    }
}

fn difference<C: Contains>(
    container: &C,
) -> <<C as Contains>::B as std::ops::Sub<<C as Contains>::A>>::Output {
    container.last() - container.first()
}

fn main() {
    let number_1 = 3;
    let number_2 = 10;

    let container = Container(number_1, number_2);

    println!(
        "Does container contain {} and {}: {}",
        &number_1,
        &number_2,
        container.contains(&number_1, &number_2)
    );
    println!("First number: {}", container.first());
    println!("Last number: {}", container.last());

    println!("The difference is: {}", difference(&container));
}

编译并运行良好:

Does container contain 3 and 10: true
First number: 3
Last number: 10
The difference is: 7

我会注意到如果 Contains 总是 将只包含数字类型,您可能可以使用 num crate 更轻松地实现这一点,如图Trait for numeric functionality in Rust .

关于rust - 我如何向编译器解释通用函数返回可用于减法的数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45731090/

相关文章:

rust - Vec中用逗号分隔的元素

rust - 如何使 std::format 中的填充填充动态?

rust - 你如何在比赛中借用可变引用?

rust - 在 Box 中指定通用实现以使用匹配项

rust - 交叉编译后缺少共享库的替代解决方案?

rust - 如果无法升级到强引用,如何从 BinaryHeap 中删除 Weak<T> 值?

http - 从网页中检索 HTML 源

generics - 为什么我的泛型函数没有为元组单态化?

linux - 无法加载redis模块,RedisJSON

rust - 由于双重借用,无法将自身作为回调参数传递