Rust中的泛型:不能将`< T as Add>::Output`除以`{float}`

5m1hhzi4  于 6个月前  发布在  其他
关注(0)|答案(2)|浏览(52)

我正在学习Rust中的泛型。我创建了一个简单的用例,使用一个函数来计算其面积。请考虑下面的例子:

#[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>不再使其通用。加上添加此子句对编译代码没有帮助。而且它确实使源代码非常混乱。
你能建议一个优雅的'教科书'解决方案,使我的基本例子工作?

fykwrbwg

fykwrbwg1#

T: std::ops::Add确保你可以计算a+b,但它不允许你计算/2.0/h。你至少需要T: std::ops::Div,这样你才能计算/h,再加上一些方法来允许/2.0
编译器试图建议一种允许除以2的方法,但还有其他方法。最简单的方法之一是确保您可以从2.0(可以表示为T: From<f32>)构造T,因为您已经需要T: std::ops::Div
此外,由于您的函数返回T类型的值,您还需要告诉编译器所有这些操作都返回T s。
完整示例:

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

cig3rfwq

cig3rfwq2#

通过使用num_traits::One来构建你需要的数字2,可以编写比Jmb的答案更通用的代码。这样,代码甚至可以处理整数(当然,有四舍五入)。

use std::ops;

fn calc_area<T>(a: T, b: T, h: T) -> T
where
    T: ops::Add<Output = T> + ops::Div<Output = T> + num_traits::One,
{
    let two = T::one() + T::one();
    return (a + b) / two / h;
}

字符串
当你想写通用的数字代码时,不要犹豫使用num_traits-这就是它的用途。你可以使用更强的绑定Num来代替所有的单独操作:

fn calc_area<T: num_traits::Num>(a: T, b: T, h: T) -> T {
    let two = T::one() + T::one();
    return (a + b) / two / h;
}

相关问题