这确实是可能的,但你需要一个新的特性和大量的混乱。
如果你从抽象开始
enum VecOrScalar<T> {
Scalar(T),
Vector(Vec<T>),
}
use VecOrScalar::*;
您想要一种使用类型转换的方法
T (hidden) -> VecOrScalar<T> -> T (known)
Vec<T> (hidden) -> VecOrScalar<T> -> Vec<T> (known)
因为这样你就可以采用“隐藏”类型T
,将其包装在 a 中并使用 aVecOrScalar
提取真实类型。T
match
你也想要
T (known) -> bool = T::Output
Vec<T> (known) -> Vec<bool> = Vec<T>::Output
但如果没有更高种类的类型,这有点棘手。相反,你可以做
T (known) -> VecOrScalar<T> -> T::Output
Vec<T> (known) -> VecOrScalar<T> -> Vec<T>::Output
如果你允许一个可以恐慌的分支。
因此,该特征将是
trait FromVecOrScalar<T> {
type Output;
fn put(self) -> VecOrScalar<T>;
fn get(out: VecOrScalar<bool>) -> Self::Output;
}
有实现
impl<T> FromVecOrScalar<T> for T {
type Output = bool;
fn put(self) -> VecOrScalar<T> {
Scalar(self)
}
fn get(out: VecOrScalar<bool>) -> Self::Output {
match out {
Scalar(val) => val,
Vector(_) => panic!("Wrong output type!"),
}
}
}
impl<T> FromVecOrScalar<T> for Vec<T> {
type Output = Vec<bool>;
fn put(self) -> VecOrScalar<T> {
Vector(self)
}
fn get(out: VecOrScalar<bool>) -> Self::Output {
match out {
Vector(val) => val,
Scalar(_) => panic!("Wrong output type!"),
}
}
}
你的类型
#[derive(Copy, Clone)]
struct Clf {
x: f64,
}
将首先实现两个分支:
impl Clf {
fn calc_scalar(self, f: f64) -> bool {
f > self.x
}
fn calc_vector(self, v: Vec<f64>) -> Vec<bool> {
v.into_iter().map(|x| self.calc_scalar(x)).collect()
}
}
然后它将通过实现FnOnce
forT: FromVecOrScalar<f64>
impl<T> FnOnce<(T,)> for Clf
where
T: FromVecOrScalar<f64>,
{
有类型
type Output = T::Output;
extern "rust-call" fn call_once(self, (arg,): (T,)) -> T::Output {
调度首先将私有类型框起来,因此您可以使用 提取它enum
,然后T::get
s 结果,再次隐藏它。
match arg.put() {
Scalar(scalar) => T::get(Scalar(self.calc_scalar(scalar))),
Vector(vector) => T::get(Vector(self.calc_vector(vector))),
}
}
}
然后,成功:
fn main() {
let c = Clf { x: 0.0 };
let v = vec![-1.0, 0.5, 1.0];
println!("{}", c(0.5f64));
println!("{:?}", c(v));
}
由于编译器可以看穿所有这些问题,因此它实际上编译为与直接调用calc_
方法基本相同的程序集。
这并不是说写作很好。像这样的超载是一种痛苦、脆弱,而且肯定是 A Bad Idea™。不要这样做,尽管知道你可以做到这一点很好。