通用数据类型的特征边界

问题描述 投票:0回答:2

我正在尝试为梯形和三角形等平面几何形状实现一个名为

Area
的基本特征。当我将数据类型修复为
f32
时,代码有效。但是,当我尝试转换此示例以应用通用数据类型时,我遇到了麻烦。请考虑下面的源代码:

pub trait Area<T> {
    fn calc_area(&self) -> T
    where
        T: std::ops::Add<Output = T>,
        T: std::ops::Div<Output = T>,
        T: From<f32>;
}

#[derive(Debug)]
pub struct Triangle<T> {
    pub a: T,
    pub b: T,
    pub c: T,
    pub area: T,
    pub perimeter: T,
}

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

impl<T> Area<T> for Trapezium<T> {
    fn calc_area(&self) -> T
    {
        return (self.a+self.b)/2.0.into()/self.h;
    }
}

fn main() {

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

编译此代码会导致以下错误:

Compiling geometric v0.1.0 (/Users/mabalenk/repo/git/rustup/src/geometric)
error[E0369]: cannot add `T` to `T`
  --> src/main.rs:46:23
   |
46 |         return (self.a+self.b)/2.0.into()/self.h;
   |                 ------^------ T
   |                 |
   |                 T
   |
help: consider restricting type parameter `T`
   |
43 | impl<T: std::ops::Add> Area<T> for Trapezium<T> {
   |       +++++++++++++++

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

我的问题是:

  1. 我不想重复我已经在特征定义中指定的绑定信息。我该如何正确做?
  2. 为什么我必须在关键字
    <T>
    impl
    Area
    之后提及通用数据类型
    Trapezium
    ?每种情况意味着什么?也许我做得太过分了?
generics rust traits
2个回答
2
投票

为了避免重复,您可以定义一个结合这些边界的辅助特征,然后在您的特征及其实现中使用此辅助特征:

pub trait Calculatable: std::ops::Add<Output = Self> + std::ops::Div<Output = Self> + From<f32> {}

pub trait Area<T>
where
    T: Calculatable,
{
    fn calc_area(&self) -> T;
}

impl<T> Area<T> for Trapezium<T>
where
    T: Calculatable,
{
    fn calc_area(&self) -> T {
        // Your implementation
    }
}

此外,代码中不同位置的

<T>
表示您正在使用泛型类型。根据我的理解,这在这种情况下意味着什么:

impl:这表明以下实现是针对泛型类型 T 的。这是一种告诉编译器这是泛型实现,而不是针对特定类型的实现。

另外,我注意到您当前在 Trapezium 中实现的 calc_area 有一个逻辑问题。公式 (self.a + self.b) / 2.0.into() / self.h 无法正确计算梯形的面积。正确的公式应该是 ((self.a + self.b) / 2.0.into()) * self.h。另外,请确保您的泛型类型 T

支持所有操作(+、/、*)

0
投票
  1. 这在这里是不可行的,因为 Rust 认为你的 struct/impl 可能需要扩展该特征界限(例如:你的

    impl
    可能需要
    Copy
    特征界限以及你需要的
    Area
    特征) .

  2. @chayim-friedman 的评论总结了答案。基本上,您编写的代码暗示了它可以接受的多种类型。要添加它,您甚至可以拥有

    impl<T, U> Area<U> for Trapezium<T>

我的建议是:

pub trait Area {
    // From @adesoji-alu's answer
    type Output: Calculatable;
    fn calc_area(&self) -> Self::Output;
}

这样做有一些优点,但主要的一个是你不能为同一个特征实现多个返回类型。

  • 使用
    num
    板条箱。无需费力地定义
    Mul
    Div
    Add
    等特征边界,只需使用
    Float
    板条箱提供的
    Integer
    num
    伞特征即可。
  • 一起摆脱泛型类型。只需使用接受任何类型数字类型(
    usize
    f32
    等)的构造函数,将它们转换为
    f32
    并按原样存储。同样,方法应该返回相同的数字类型。当您以后想要实现其他功能时,这可能会为您省去很多麻烦(例如:如果您必须找出一个形状是否适合另一个形状怎么办?如果这两个具有不同的类型,您必须将它们转换为通用的类型)第一个)
© www.soinside.com 2019 - 2024. All rights reserved.