我正在尝试为梯形和三角形等平面几何形状实现一个名为
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
我的问题是:
<T>
、impl
和 Area
之后提及通用数据类型 Trapezium
?每种情况意味着什么?也许我做得太过分了?为了避免重复,您可以定义一个结合这些边界的辅助特征,然后在您的特征及其实现中使用此辅助特征:
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
支持所有操作(+、/、*)这在这里是不可行的,因为 Rust 认为你的 struct/impl 可能需要扩展该特征界限(例如:你的
impl
可能需要 Copy
特征界限以及你需要的 Area
特征) .
@chayim-friedman 的评论总结了答案。基本上,您编写的代码暗示了它可以接受的多种类型。要添加它,您甚至可以拥有
impl<T, U> Area<U> for Trapezium<T>
。
我的建议是:
Area
特征: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
并按原样存储。同样,方法应该返回相同的数字类型。当您以后想要实现其他功能时,这可能会为您省去很多麻烦(例如:如果您必须找出一个形状是否适合另一个形状怎么办?如果这两个具有不同的类型,您必须将它们转换为通用的类型)第一个)