我正在学习Rust中的泛型.我创建了一个带有计算其面积的函数的Alzium struct 的简单用例.请考虑下面的例子:

#[derive(Debug)]
struct Trapezium<T> {
    a: T,
    b: T,
    h: T,
    area: T,
    perimeter: T,
}

fn calc_area<T: std::ops::Add>(a: T, b: T, h: T) -> T {

    return (a+b)/2.0/h;
}

fn main() {

    let mut t = Trapezium {a: 3.1, b: 6.9, h: 2.5, area: 0.0, perimeter: 0.0};
    t.area    = calc_area(t.a, t.b, t.h);
    println!("t: {:?}", t);
}

我在calc_area的函数中遇到了问题,因为除以float64.请在下面找到我的编译错误:

Compiling geometric v0.1.0 (/Users/mabalenk/repo/git/rustup/src/geometric)
error[E0369]: cannot divide `<T as Add>::Output` by `{float}`
  --> src/main.rs:12:17
   |
12 |     return (a+b)/2.0/h;
   |            -----^--- {float}
   |            |
   |            <T as Add>::Output
   |
help: consider further restricting the associated type
   |
10 | fn calc_area<T: std::ops::Add>(a: T, b: T, h: T) -> T where <T as Add>::Output: Div<f64> {
   |                                                       ++++++++++++++++++++++++++++++++++

For more information about this error, try `rustc --explain E0369`.
error: could not compile `geometric` (bin "geometric") due to previous error

我对增加where <T as Add>::Output: Div<f64>条款的建议感到担忧.Div<f64>不再使其成为通用产品.另外,添加此子句无助于编译代码.而且,它确实使源代码变得非常混乱.

你能推荐一个优雅的"教科书"解决方案,让我的基本例子发挥作用吗?

推荐答案

T: std::ops::Add可以确保您可以计算a+b,但它不允许您计算/2.0/h.您至少需要T: std::ops::Div,这样才能计算/h,再加上允许/2.0的某种方法.

编译器正试图提出一种允许除以2的方法,但还有其他方法.既然您已经需要T: std::ops::Div,那么最简单的方法之一就是确保您可以从2.0构造一个T,它可以表示为T: From<f32>.

此外,因为您的函数返回一个T类型的值,所以您还需要告诉编译器所有这些操作都返回T.

完整示例:

fn calc_area<T>(a: T, b: T, h: T) -> T
where
    T: std::ops::Add<Output = T>,
    T: std::ops::Div<Output = T>,
    T: From<f32>,
{
    return (a+b)/2.0.into()/h;
}

Playground

Rust相关问答推荐

go 掉包装 struct 中的泛型

何时可以在Rust中退出异步操作?

在Rust中赋值变量有运行时开销吗?

当一个箱子有自己的依赖关系时,两个人如何克服S每箱1库+n箱的限制?

如何在Bevy/Rapier3D中获得碰撞机的计算质量?

为什么';t std::cell::ref使用引用而不是非空?

将Vec<;U8&>转换为Vec<;{Float}&>

如何对一个特征的两个实现进行单元测试?

Rust FFI 和 CUDA C 性能差异

需要一个有序向量来进行 struct 初始化

Rust中的一生语法有什么作用?

Rust中的位移操作对范围有什么影响?

实现AsyncWrite到hyper Sender时发生生命周期错误

从光标位置旋转精灵

在给定 Rust 谓词的情况下,将 Some 转换为 None 的惯用方法是什么?

如果不满足条件,如何在 Rust 中引发错误

在每个循环迭代中删除borrow

如何制作具有关联类型的特征的类型擦除版本?

如何在 Rust 中构建一个 str

为移动和借位的所有组合实现 Add、Sub、Mul、Div