【问题标题】:Why is it necessary to add redundant trait bounds even though my trait uses those same traits as bounds?即使我的特征使用与边界相同的特征,为什么还要添加冗余特征边界?
【发布时间】:2018-03-23 03:38:47
【问题描述】:

我一直在尝试编写一个特征,该特征需要一个类型来实现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。后三个impls 是按照第一个来实现的。
  • Addable 是我要演示的核心特征。可添加的东西应该允许它们自己和它们的引用被添加,结果是Self。特别是,在add_stuff 中,我希望表达式x + y + x 有效,其中x + y 给出一个非引用,可以添加x(它没有被移出,因为它是一个引用)来产生另一个非参考。
  • 我没有收到编译器关于在MyVec 上实现Addable 特征的任何投诉。具体来说,编译器似乎认识到上述impls 满足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,我不完全理解但可能相关?这表明这确实是 Rust 中的一个错误(很长时间没有修复)。

【问题讨论】:

    标签: rust traits


    【解决方案1】:

    您遇到了 Rust 编译器目前的一个缺点。 RFC 2089 提议让它如你所愿工作,并于2017年12月被接受。

    但是,截至今天,该功能尚未实现。 tracking issue for the implementation 还没有看到太多活动,所以看起来实施还没有开始。似乎需要对编译器的 trait bound 处理进行一些根本性的改进,才能有效地实现这一特定功能(搜索关键字:chalk)。

    【讨论】:

    • 好吧,至少我的理解是正确的,一旦 RFC 完全实施,我总是可以删除那些多余的 trait bound。虽然这似乎是一个重大缺陷,但至少 RFC 最近已被接受,所以我希望它会获得一些牵引力。
    猜你喜欢
    • 2016-11-29
    • 2020-08-17
    • 2019-12-17
    • 2016-12-23
    • 1970-01-01
    • 2016-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多