這確實是可能的,但你需要一個新的特點和一堆爛攤子。
如果你開始與抽象
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
但沒有HKT這是一個有點棘手。相反,你可以做
T (known) -> VecOrScalar<T> -> T::Output
Vec<T> (known) -> VecOrScalar<T> -> Vec<T>::Output
如果你允許一個可以恐慌的分支。
這種特點將因此是
trait FromVecOrScalar<T> {
fn put(self) -> VecOrScalar<T>;
type Output;
fn get(out: VecOrScalar<bool>) -> Self::Output;
}
與實施方式
impl<T> FromVecOrScalar<T> for T {
fn put(self) -> VecOrScalar<T> {
Scalar(self)
}
type Output = bool;
fn get(out: VecOrScalar<bool>) -> Self::Output {
match out {
Scalar(val) => val,
Vector(_) => panic!("Wrong output type!"),
}
}
}
impl<T> FromVecOrScalar<T> for Vec<T> {
fn put(self) -> VecOrScalar<T> {
Vector(self)
}
type Output = Vec<bool>;
fn get(out: VecOrScalar<bool>) -> Self::Output {
match out {
Vector(val) => val,
Scalar(_) => panic!("Wrong output type!"),
}
}
}
你的類
#[derive(Copy, Clone)]
struct Clf {
x: f64,
}
將首先執行兩個B牧場:
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>
impl<T> FnOnce<(T,)> for Clf
where T: FromVecOrScalar<f64>
{
通過實施FnOnce
派遣與類型
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_
方法。
但是,這並不是說這是很好的寫作。這樣的超載是一種痛苦,脆弱,當然也是一個壞主意™。不要這樣做,儘管知道你可以。
非常感謝! – asdetrefle