Generics 如何要求泛型类型在泛型函数中实现像Add、Sub、Mul或Div这样的操作?

Generics 如何要求泛型类型在泛型函数中实现像Add、Sub、Mul或Div这样的操作?,generics,rust,Generics,Rust,我试图在Rust中实现一个泛型函数,其中参数的唯一要求是应该定义乘法运算。我试图实现一个通用的“power”,但将使用一个更简单的cube函数来说明问题: use std::ops::Mul; fn cube<T: Mul>(x: T) -> T { x * x * x } fn main() { println!("5^3 = {}", cube(5)); } 使用std::ops::Mul; fn立方(x:T)->T{ x*x*x } fn main(

我试图在Rust中实现一个泛型函数,其中参数的唯一要求是应该定义乘法运算。我试图实现一个通用的“power”,但将使用一个更简单的
cube
函数来说明问题:

use std::ops::Mul;

fn cube<T: Mul>(x: T) -> T {
    x * x * x
}

fn main() {
    println!("5^3 = {}", cube(5));
}
使用std::ops::Mul;
fn立方(x:T)->T{
x*x*x
}
fn main(){
println!(“5^3={}”,立方体(5));
}
编译时出现以下错误:

error[E0369]:二进制操作“*”不能应用于类型“::输出`
-->src/main.rs:4:5
|
4 | x*x*x
|     ^^^^^^^^^
|
=注意:`::Output可能缺少`std::ops::Mul`的实现`

这是什么意思?我选错了吗?我该如何解决这个问题呢?

让我们把你的例子分解一下:

fn cube<T: Mul>(x: T) -> T {
    let a = x * x;
    let b = a * x;
    b
}
不幸的是,这会产生两个类似的错误:

错误[E0382]:使用移动值:`x`
-->src/lib.rs:6:9
|
6 | x*x*x
|-^移动后此处使用的值
|     |
|价值转移到这里
|
=注意:发生移动是因为'x'具有类型'T',而该类型不实现'Copy'特性
这是因为,所以我们添加了
Copy
,这样我们就可以复制这些值

我还切换到了
where
子句,因为我更喜欢它,而且有这么多的内联语句是不方便的:

fn cube<T>(x: T) -> T
where
    T: Mul<Output = T> + Copy
{
    x * x * x
}
fn立方体(x:T)->T
哪里
T:Mul+Copy
{
x*x*x
}
另见:


绑定
T:Mul
并不意味着二进制运算符的结果也是
T
类型。结果类型是此特征的关联类型:
Output

另一个问题是,在Rust 1.0之前,操作员特征从按参考传递切换到按值传递。在泛型代码中,这可能有点麻烦(至少现在是这样),因为除非您还要求类型为
Copy
,否则这些运算符会使用它们的操作数

为了完整起见(如果您不想要求
复制
),让我添加一些关于可能的替代方向的信息

为了通用代码,鼓励“数字类型”的作者提供这些运算符特性的其他非消耗性实现,这样您就不需要
复制
克隆
。例如,标准库已经提供了以下实现:

f64实现Mul
f64实现Mul
&f64实现Mul
&f64实现Mul
每个实现都有
f64
作为
Output
类型。直接利用这些特征并不漂亮:

fn cube<T>(x: &T) -> T
where
    for<'a> T: Mul<&'a T, Output = T>,
    for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
    x * x * x
}

我认为可以肯定地说,这方面的情况会有所改善。目前,在Rust中通用地实现数值算法的能力不如我所希望的那么好。

请您也解释一下(或只是给出一个链接)“where For”表示法,我以前没有见过。where子句是约束通用参数的更通用的方法。它们是通过
fn cube<T>(x: &T) -> T
where
    for<'a> T: Mul<&'a T, Output = T>,
    for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
    x * x * x
}
use std::ops::Mul;

pub trait Mul2
where
    Self: Mul<Self, Output = Self>,
    Self: for<'a> Mul<&'a Self, Output = Self>,
    for<'a> &'a Self: Mul<Self, Output = Self>,
    for<'a, 'b> &'a Self: Mul<&'b Self, Output = Self>,
{
}

impl<T> Mul2 for T
where
    T: Mul<T, Output = T>,
    T: for<'a> Mul<&'a T, Output = T>,
    for<'a> &'a T: Mul<T, Output = T>,
    for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
}

fn cube<T: Mul2>(x: &T) -> T {
    x * x * x
}

fn main() {
    let c = cube(&2.3);
    println!("Hello, world! {}", c)
}