我想为泛型类型结构实现一个特性。特征块内的方法必须返回非泛型类型。我在尝试演员时遇到了问题:
struct Rectangle<T> {
x: T,
y: T,
width: T,
height: T,
}
trait Area {
fn area(&self) -> f64;
}
impl<T> Area for Rectangle<T>
where T: std::ops::Mul<Output=T>
{
fn area(&self) -> f64 {
let t_area = self.height * self.width;
let f_area = t_area as f64;
f_area
}
}
fn main() {
let sq = Rectangle { x: 0, y: 0, height: 1, width: 1 };
println!("{}", sq.area());
}
编译器输出为:
error: non-scalar cast: `T` as `f64`
--> src/main.rs:22:22
|
22 | let f_area = t_area as f64;
| ^^^^^^^^^^^^^
我可以在不使用不安全的阻止的情况下将T
投射到f64
吗?
答案 0 :(得分:3)
我可以,不使用不安全的阻止,将
T
投射到f64
吗?
不,并且有很多充分的理由。 T
可以是任何类型,因此它不需要与f64
完全兼容或类似于。您对T
唯一了解的是,它实现了std::ops::Mul<Output=T>
。但这并没有帮助,因为这个特性也没有说明f64
。
因此可以做的是将T
绑定为std::ops::Mul<Output=f64>
。这意味着将两个T
相乘会产生f64
。然后你的函数可以工作(即使没有as f64
强制转换),但是你的impl方式不那么通用了。
解决这个问题的正确方法是抽象出多种数字。值得庆幸的是,num-traits
crate已经做到了。特别是,您可能对ToPrimitive
trait感兴趣。那你的impl应该看起来有点像:
use num_traits::ToPrimitive;
impl<T> Area for Rectangle<T>
where T: std::ops::Mul
<T as std::ops::Mul>::Output: ToPrimitive
{
fn area(&self) -> f64 {
let t_area = self.height * self.width;
t_area.to_f64().unwrap()
}
}
小问题:我们这里有unwrap()
,当乘法结果无法转换为f64
时会发生恐慌。我不太确定为什么会发生这种情况,但我们需要注意这一点。如果没有这样的unwrap()
,可能会有更好的解决方案。
您当然也可以创建自己的特质。类似的东西:
trait AsF64 {
fn cast(self) -> f64;
}
impl AsF64 for i32 {
fn cast(self) -> f64 { self as f64 }
}
// more impls for u32, u16, i16, ...
然后impl为<T as std::ops::Mul>::Output: AsF64
。
答案 1 :(得分:3)
我可以,不使用不安全的阻止,将
T
投射到f64
吗?
T
是什么?将u8
转换为f64
的代码肯定与将u64
转换为f64
的代码不同(毕竟后者可能会失败)。
在我看来,你前面有两条路:
Area
通用超过T
,从而返回T
T
约束为可以转换为f64
我将展示后者:
impl<T> Area for Rectangle<T>
where T: std::ops::Mul<Output=T> + Clone + std::convert::Into<f64>
{
fn area(&self) -> f64 {
self.height.clone().into() * self.width.clone().into()
}
}