这确实是可能的,但需要一个新的特性和大量的混乱。
如果您从抽象开始
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
,用
VecOrScalar
包装起来,并使用
match
提取真实的类型
T
。
你还需要...
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
如果您允许存在可能会出现panic的分支。
因此,该特质将是:
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()
}
}
然后它将通过为 T: FromVecOrScalar<f64>
实现 FnOnce
来进行调度。
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
获取结果,以再次隐藏它。
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_
方法基本相同的汇编代码。
这并不意味着写起来很好。像这样的重载是痛苦的、易碎的,并且绝对是一个坏主意™。不要这样做,但知道你可以这样做也没问题。