我正在尝试创建一个函数向量,这个想法是第一个函数的输出将被传递到第二个函数的输入等等。
我很难理解如何(如果可能的话)将其编码到Rust类型系统中。我尝试使用泛型但遇到了问题,因为泛型期望输入和输出对于函数向量中的每个元素总是相同的。
例如,功能一可能是i32 -> String
,功能二String -> bool
和功能三bool -> f64
。
我的尝试:
fn main() {
let mut funcs: Vec<Box<Fn(i32) -> i32>> = Vec::new();
funcs.push(Box::new(|a| a * 2));
funcs.push(Box::new(|b| b * 3));
// This won't work since it's not a Fn(i32) -> i32
funcs.push(Box::new(|c| String::from(c)));
// How can I create a vec of Fn(anything) -> anything where the anythings can be different for every item in the vector?
}
我开始认为Rust中唯一可行的方法是使用宏创建特定数量元素的结构。
答案 0 :(得分:3)
您可以在Box
中使用Any
特征,但是:
use std::any::Any;
pub type FnAnyToAny = Fn(Box<Any>) -> Box<Any>;
pub fn make_any_to_any<I, O, F>(f: F) -> Box<FnAnyToAny>
where
I: 'static,
O: 'static,
F: Fn(I) -> O + 'static,
{
Box::new(move |i: Box<Any>| -> Box<Any> {
let i: Box<I> = Box::<Any + 'static>::downcast(i).expect("wrong input type");
Box::new(f(*i))
})
}
pub fn run_all_any<I, O>(funcs: &Vec<Box<FnAnyToAny>>, i: I) -> O
where
I: 'static,
O: 'static,
{
let i: Box<Any> = Box::new(i);
let o = funcs.iter().fold(i, |acc, f| f(acc));
let o: Box<O> = Box::<Any + 'static>::downcast(o).expect("wrong output type");
*o
}
fn main() {
let mut funcs: Vec<Box<FnAnyToAny>> = Vec::new();
funcs.push(make_any_to_any(|a: i32| a * 2));
funcs.push(make_any_to_any(|b: i32| b * 3));
funcs.push(make_any_to_any(|c: i32| format!("{}", c)));
println!("{:?}", run_all_any::<i32, String>(&funcs, 4));
}
在您提到的评论中,您实际上想要处理大量输入项并在单独的线程中运行每个函数。我认为rayon
箱子应该处理这个问题:
extern crate rayon;
use rayon::prelude::*;
fn main() {
let input = vec![1, 2, 3, 4];
// without parallel processing you'd start with:
// let output = input.into_iter()
let output = input
.into_par_iter()
.map(|a| a * 2)
.map(|b| b * 3)
.map(|c| format!("{}", c))
.collect::<Vec<_>>();
println!("{:?}", output);
}
如果你真的等了很多,例如对于网络数据(而不是实际需要CPU时间),您可能需要查看futures
包,尤其是futures::stream::Stream
。