首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何要求泛型类型在泛型函数中实现像Add、Sub、Mul或Div这样的操作?

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

Stack Overflow用户
提问于 2015-03-21 15:18:36
回答 2查看 5.7K关注 0票数 34

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

代码语言:javascript
复制
use std::ops::Mul;

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

fn main() {
    println!("5^3 = {}", cube(5));
}

在编译时,我会得到以下错误:

代码语言:javascript
复制
error[E0369]: binary operation `*` cannot be applied to type `<T as std::ops::Mul>::Output`
 --> src/main.rs:4:5
  |
4 |     x * x * x
  |     ^^^^^^^^^
  |
  = note: an implementation of `std::ops::Mul` might be missing for `<T as std::ops::Mul>::Output`

这是什么意思?我选择了错误的特质吗?我怎么解决这个问题?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-03-21 15:27:55

让我们详细分析一下您的示例:

代码语言:javascript
复制
fn cube<T: Mul>(x: T) -> T {
    let a = x * x;
    let b = a * x;
    b
}

a和b的类型是什么?在这种情况下,a的类型是<T as std::ops::Mul>::Output -从错误消息中听起来很熟悉吗?然后,我们再次尝试将该类型乘以x,但不能保证Output可以乘以任何东西!

让我们做一件最简单的事情,说T * T需要生成一个T

代码语言:javascript
复制
fn cube<T: Mul<Output = T>>(x: T) -> T {
    x * x * x
}

不幸的是,这产生了两个类似的错误:

代码语言:javascript
复制
error[E0382]: use of moved value: `x`
 --> src/lib.rs:6:9
  |
6 |     x * x * x
  |     -   ^ value used here after move
  |     |
  |     value moved here
  |
  = note: move occurs because `x` has type `T`, which does not implement the `Copy` trait

这是因为 trait takes arguments by value,所以我们添加了Copy,这样就可以复制值。

我还切换到了where子句,因为我更喜欢它,有那么多内联代码是很困难的:

代码语言:javascript
复制
fn cube<T>(x: T) -> T
where
    T: Mul<Output = T> + Copy
{
    x * x * x
}

另请参阅:

票数 41
EN

Stack Overflow用户

发布于 2015-03-21 22:34:52

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

另一个问题是,在锈菌1.0之前,操作者的特征从按引用传递到按值传递。在泛型代码中,这可能有点麻烦(至少现在是这样),因为这些操作符使用它们的操作数,除非您还要求类型为Copy。

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

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

代码语言:javascript
复制
 f64 implements Mul< f64>
 f64 implements Mul<&f64>
&f64 implements Mul< f64>
&f64 implements Mul<&f64>

这些实现中的每一个都有f64作为Output类型。直接利用这些特性是不太好的:

代码语言:javascript
复制
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
}

最终,我们可能会得到一些(稍高的)水平特征,这将减少噪音。例如:T: Mul2可能意味着T: Mul<T> + Mul<&T>和&T: Mul<T> + Mul<&T>,但是在编写这篇文章时,Rust编译器似乎无法处理这个问题。至少我无法成功地编译以下代码:

代码语言:javascript
复制
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)
}

我认为可以肯定地说,这一领域的情况会有所改善。目前,在Rust中通用实现数字算法的能力并不像我希望的那样好。

票数 19
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29184358

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档