绑定T: Mul 并不意味着二元运算符的结果也是T 类型。结果类型是该特征的关联类型:Output。
另一个问题是在 Rust 1.0 之前,操作符特征从传递引用切换到传递值。在通用代码中,这可能有点让人头疼(至少现在是这样),因为这些运算符使用它们的操作数,除非您还要求类型为Copy。
为了完整起见(如果您不想要求Copy),让我添加一些关于可能的替代方向的信息。
为了通用代码,鼓励“数字类型”的作者提供这些运算符特征的额外非消耗实现,这样您就不需要Copy 或Clone .例如,标准库已经提供了以下实现:
f64 implements Mul< f64>
f64 implements Mul<&f64>
&f64 implements Mul< f64>
&f64 implements Mul<&f64>
每个实现都有f64 作为Output 类型。直接利用这些特征并不漂亮:
fn cube<T>(x: &T) -> T
where
for<'a> T: Mul<&'a T, Output = T>,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
x * x * x
}
最终,我们可能会获得一些(稍微)更高级别的特征,这将减少噪音。例如:T: Mul2 可以暗示 T: Mul<T> + Mul<&T> 和 &T: Mul<T> + Mul<&T>,但在撰写本文时,Rust 编译器似乎无法处理这个问题。至少我无法成功编译以下代码:
use std::ops::Mul;
pub trait Mul2
where
Self: Mul<Self, Output = Self>,
Self: for<'a> Mul<&'a Self, Output = Self>,
for<'a> &'a Self: Mul<Self, Output = Self>,
for<'a, 'b> &'a Self: Mul<&'b Self, Output = Self>,
{
}
impl<T> Mul2 for T
where
T: Mul<T, Output = T>,
T: for<'a> Mul<&'a T, Output = T>,
for<'a> &'a T: Mul<T, Output = T>,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
}
fn cube<T: Mul2>(x: &T) -> T {
x * x * x
}
fn main() {
let c = cube(&2.3);
println!("Hello, world! {}", c)
}
我认为可以肯定地说这方面的情况会有所改善。目前,在 Rust 中通用实现数值算法的能力并没有我希望的那么好。