不久前,我开始研究为斐波那契数列编写一个通用迭代器
既可以接受原始数字也可以接受自定义类型(例如bignums)。无法获得适用于两种原始类型的版本后
bignums,我偶然发现了这个问题:

How to write a trait bound for adding two references of a generic type?

其中使用所谓的高等特质界限来解决此问题
特别的问题。

但是现在,我正在尝试使用类似的策略来使用*_assign运算符。特别是,我正在尝试获得与此类似的内容
在职的:

use std::ops::{Add, AddAssign};

fn add_test<'a, T>(x: &'a T, y: &'a T) -> T
where
    for<'b> &'b T: Add<Output = T>,
{
    x + y
}

fn add_assign_test<'a, T>(x: &'a mut T, y: &'a T) -> T
where
    for<'b> &'b mut T: AddAssign<&'b T>,
    T: Clone,
{
    x += y;
    x.clone()
}

fn main() {
    println!("add_test()={}", add_test(&1, &2));
    println!("add_assign_test()={}", add_assign_test(&mut 2, &2));
}
add_test()可以按预期工作,但是我无法让add_assign_test()以类似方式工作。我收到的错误提示可能实际上不存在针对原始类型的这种行为的实现:

error[E0277]: the trait bound `for<'b> &'b mut _: std::ops::AddAssign<&'b _>` is not satisfied
  --> src/main.rs:21:38
   |
21 |     println!("add_assign_test()={}", add_assign_test(&mut 2, &2));
   |                                      ^^^^^^^^^^^^^^^ no implementation for `&'b mut _ += &'b _`
   |
   = help: the trait `for<'b> std::ops::AddAssign<&'b _>` is not implemented for `&'b mut _`
   = note: required by `add_assign_test`

我可以创建一个宏来为这些运算符创建实现,该实现实际上采用对原始类型的引用,但这似乎有点浪费。还有其他方法可以达到相同的效果吗?

最佳答案

在您的代码中只是一个小小的疏忽。让我们看一下特征:

pub trait AddAssign<Rhs = Self> {
    fn add_assign(&mut self, rhs: Rhs);
}

该方法的接收者已经是&mut self而不是self。您必须对Add进行额外工作的原因是因为它接受self作为接收者。对于AddAssign来说,这意味着:如果类型T实现AddAssign,则可以在add_assign()上调用&mut T方法!

因此,与其编写:
where for <'b> &'b mut T: AddAssign<&'b T>,

...你会这样写:
where for <'b> T: AddAssign<&'b T>,

(到目前为止,其他行均未更改)

但是,您注意到代码still won't compile:

error[E0277]: the trait bound `for<'b> {integer}: std::ops::AddAssign<&'b {integer}>` is not satisfied
  --> src/main.rs:13:38
   |
13 |     println!("add_assign_test()={}", add_assign_test(&mut 2, &2));
   |                                      ^^^^^^^^^^^^^^^ no implementation for `{integer} += &'b {integer}`
   |
   = help: the trait `for<'b> std::ops::AddAssign<&'b {integer}>` is not implemented for `{integer}`
   = note: required by `add_assign_test`

原因很简单:对于基本类型根本没有AddAssign的实现,该类型将不可变的引用作为rhs(Docs)。我不知道这是否是个疏忽-值得在Rust repo 上发布一个问题。

为了验证上述代码是否有效,我编写了自己的类型并适当地实现了AddAssign:Playground

09-03 21:30