Это действительно возможно, но вам нужна новая черта и тонна беспорядка.
Если вы начинаете с абстракцией
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
и извлечь реальный тип T
с match
.
Вы также хотите
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,
}
будет первым реализовать два б ранчо:
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
для T: 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
с результатом, чтобы скрыть его снова.
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));
}
Поскольку компилятор может видеть через все это malarky, он на самом деле компилирует прочь полностью в основном той же сборки, как прямой вызов к calc_
методов.
Но это не значит, что приятно писать. Перегрузка, как это, боль, хрупкость и, безусловно, Плохая идея. Не делай этого, хотя прекрасно знать, что можешь.
Спасибо большое! – asdetrefle