绑定的
T: Mul
并不意味着二元运算符的结果也是类型
T
。结果类型是此 trait 的一个关联类型:
Output
。
另一个问题是,在 Rust 1.0 之前,操作符 trait 从按引用传递切换到按值传递。在通用代码中,这可能有点麻烦(至少现在是这样),因为这些操作符会消耗它们的操作数,除非你还要求这些类型是
Copy
。
只是为了完整性(以防你不想要求
Copy
),让我添加一些关于可能的替代方向的信息。
为了通用代码的缘故,“数字类型”的作者被鼓励提供这些操作符 trait 的额外的、非消耗性的实现,这样你就不需要
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语言通用实现数值算法的能力还不如我所期望的那样好。
for<'a>
符号是在 RFC 387 中引入的:https://github.com/rust-lang/rfcs/blob/master/text/0387-higher-ranked-trait-bounds.md。 - Chris Emerson