Dies ist in der Tat möglich, aber Sie brauchen eine neue Eigenschaft und eine Tonne Chaos.
Wenn Sie mit der Abstraktion beginnen
enum VecOrScalar<T> {
Scalar(T),
Vector(Vec<T>),
}
use VecOrScalar::*;
Sie eine Art und Weise wollen die Art Transformationen verwenden
T (hidden) -> VecOrScalar<T> -> T (known)
Vec<T> (hidden) -> VecOrScalar<T> -> Vec<T> (known)
denn dann können Sie eine „versteckte“ Art nehmen T
, wickeln Sie es in ein VecOrScalar
und extrahiere den echten Typ T
mit einem match
.
Sie wollen auch
T (known) -> bool = T::Output
Vec<T> (known) -> Vec<bool> = Vec<T>::Output
aber ohne HKT das ist ein bisschen schwierig. Stattdessen können Sie tun
T (known) -> VecOrScalar<T> -> T::Output
Vec<T> (known) -> VecOrScalar<T> -> Vec<T>::Output
wenn Sie für eine Branche, die in Panik geraten können erlauben.
wird das Merkmal
trait FromVecOrScalar<T> {
fn put(self) -> VecOrScalar<T>;
type Output;
fn get(out: VecOrScalar<bool>) -> Self::Output;
}
mit Implementierungen
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!"),
}
}
}
sein damit Ihre Klasse
#[derive(Copy, Clone)]
struct Clf {
x: f64,
}
zunächst die beiden b implementieren Ranches:
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()
}
}
Dann wird es durch FnOnce
für die Umsetzung Versand T: FromVecOrScalar<f64>
impl<T> FnOnce<(T,)> for Clf
where T: FromVecOrScalar<f64>
{
mit Typ
type Output = T::Output;
extern "rust-call" fn call_once(self, (arg,): (T,)) -> T::Output {
Die Versand ersten Boxen des privaten Typ, so dass Sie es mit dem Extrakt können enum
und dann T::get
s das Ergebnis, um es wieder zu verstecken.
match arg.put() {
Scalar(scalar) =>
T::get(Scalar(self.calc_scalar(scalar))),
Vector(vector) =>
T::get(Vector(self.calc_vector(vector))),
}
}
}
Dann Erfolg:
fn main() {
let c = Clf { x : 0.0 };
let v = vec![-1.0, 0.5, 1.0];
println!("{}", c(0.5f64));
println!("{:?}", c(v));
}
Da der Compiler durch alle diese malarky sehen können, es kompiliert tatsächlich vollständig auf die im Grunde die gleiche Anordnung als direkter Aufruf an die calc_
Methoden entfernt.
Aber das ist nicht zu sagen, es ist schön zu schreiben. So zu überladen ist ein Schmerz, zerbrechlich und ganz sicher A Bad Idea ™. Tun Sie es nicht, obwohl es gut ist zu wissen, dass Sie es können.
Vielen Dank Kumpel! – asdetrefle