I'm working on some code where I'm interested in a lazy-evaluated function chain. In other words, it stores all the operations you want, and only evaluates them all together.
This is very easy when all the functions in the chain take the same type and return the same type. However, I'm stuck on how to make this work when the chain of functions returns a different type each time. This easy case can be seen in the following code:
struct FuncChain<T> {
funcs: Vec<fn(T) -> T>
}
impl<T> FuncChain<T> {
fn call(&self, input: T) -> T {
self.funcs.iter().fold(input, |prev, func| func(prev))
}
}
fn main(){
let fc = FuncChain {
funcs: vec![
|x| x + 1,
|x| x + 2,
|x| x * 2,
|x| x - 2,
]
};
println!("{}", fc.call(1));
}
So in this case we go i32 -> i32 -> i32 -> i32 -> i32
.
What I want to do is a more general case where we go A -> B -> C -> D -> E
, meaning that the funcs
vector contains: fn(A) -> B
, fn(B) -> C
, fn(C) -> D
, and fn(D) -> E
. But how can this type definition be assigned to a struct? I can't create a vector with heterogeneous types, and even if I could, what would the type signature of the struct be?
I could make a recursive type definition perhaps, where the FuncChain
holds a pointer to the first function object, and also the next object in the chain :
struct FuncChain<S, T, U> {
func: fn(S) -> T,
next: FuncChain<T, U, ?>
}
impl<S, T, U> FuncChain<S, T, U> {
fn call(&self, input: T) -> T {
self.funcs.iter().fold(input, |prev, func| func(prev))
}
}
fn main(){
let fc = FuncChain {
funcs: vec![
|x| x.toString(),
|x| u8::fromStr(x),
|x| x.toString(),
|x| i32::fromStr(x),
]
};
println!("{}", fc.call(1));
}
However of course this won't work, because I can't know the output type of next
.
How can this be done?
` and `func: fn(T, U)`.– Masklinn Nov 15 '21 at 14:38