首页 文章

为什么有必要添加冗余的特征边界,即使我的特征使用与边界相同的特征?

提问于
浏览
1

我一直在尝试编写一个特征,它需要一个类型来实现 Add (以及向下空间的其他操作)以及它自己以及它的引用 . 以下是一个小例子,说明我遇到的问题:

use std::ops::Add;

#[derive(Debug)]
struct MyVec<T>(Vec<T>);

impl<'a, 'b, T: Copy + Add> Add<&'a MyVec<T>> for &'b MyVec<T> {
    type Output = MyVec<T::Output>;
    fn add(self, other: &'a MyVec<T>) -> Self::Output {
        /* ... */
    }
}
impl<'a, T: Copy + Add> Add<MyVec<T>> for &'a MyVec<T> {
    /* ... */
}
impl<'a, T: Copy + Add> Add<&'a MyVec<T>> for MyVec<T> {
    /* ... */
}
impl<T: Copy + Add> Add<MyVec<T>> for MyVec<T> {
    /* ... */
}

trait Addable: Add<Self, Output = Self>
where
    Self: Sized,
    for<'a> &'a Self: Add<Self, Output = Self>,
    for<'b> Self: Add<&'b Self, Output = Self>,
    for<'a, 'b> &'a Self: Add<&'b Self, Output = Self>,
{
}

impl<T: Copy + Add<Output = T>> Addable for MyVec<T> {}

fn add_stuff<'a, 'b, T: Addable>(x: &'a T, y: &'b T) -> T {
    x + y
}

fn main() {
    let v = MyVec(vec![1, 2, 3]);
    let w = MyVec(vec![2, 4, 6]);
    println!("{:?}", add_stuff(&v, &w));
}
  • 我使用 newtype 模式创建了 Vec 的别名,因此我可以在外部结构( Vec )上实现外部特征( Add ) .

  • 我为 MyVec 实现了 Add 及其引用 . 关联类型 Output 始终是(未引用) MyVec . 后三个 impl 是按照第一个实现的 .

  • Addable 是我想演示的核心特征 . 可添加的东西应该允许自己和它们的引用被添加,结果是 Self . 特别是,在 add_stuff 中,我希望表达式 x + y + x 有效,其中 x + y 给出一个非ref,可以添加 x (由于它是一个ref而没有移出,因为它是一个ref)来产生另一个非ref .

  • 我没有收到编制者关于 MyVecAddable 特征实施的任何投诉 . 具体来说,编译器似乎认识到上述 impl s满足 where 子句中的边界 .

但是,我得到以下编译器错误:

error[E0277]: the trait bound `for<'a> &'a T: std::ops::Add<T>` is not satisfied
  --> src/main.rs:33:1
   |
33 | / fn add_stuff<'a, 'b, T: Addable>(x: &'a T, y: &'b T) -> T {
34 | |     x + y
35 | | }
   | |_^ no implementation for `&'a T + T`
   |
   = help: the trait `for<'a> std::ops::Add<T>` is not implemented for `&'a T`
   = help: consider adding a `where for<'a> &'a T: std::ops::Add<T>` bound
   = note: required by `Addable`

error[E0277]: the trait bound `for<'a, 'b> &'a T: std::ops::Add<&'b T>` is not satisfied
  --> src/main.rs:33:1
   |
33 | / fn add_stuff<'a, 'b, T: Addable>(x: &'a T, y: &'b T) -> T {
34 | |     x + y
35 | | }
   | |_^ no implementation for `&'a T + &'b T`
   |
   = help: the trait `for<'a, 'b> std::ops::Add<&'b T>` is not implemented for `&'a T`
   = help: consider adding a `where for<'a, 'b> &'a T: std::ops::Add<&'b T>` bound
   = note: required by `Addable`

这可以通过使用编译器建议的 where 子句修改 add_stuff 函数来修复:

where
    for<'c, 'd> &'c T: Add<&'d T, Output = T>,
    for<'c> &'c T: Add<T, Output = T>,

我不明白为什么这是必要的 . 我想通过在特征的定义中指定一个绑定,我可以依赖于实现该特征的任何类型的绑定?必须添加这些 where 条款每次都违背我的 Addable 特征的全部要点 .

谷歌搜索提出this GitHub issue我已经修复了很长时间了 .

1 回答

  • 2

    你已经遇到了Rust编译器的缺点 . RFC 2089建议使其按预期工作,并于2017年12月被接受 .

    但是,截至今天,该功能尚未实施 . tracking issue for the implementation甚至还没有开始 . 在有效实现此特定功能之前,似乎必须对编译器的特征绑定处理进行一些基本改进(搜索关键字:粉笔) .

相关问题