我有一个用例,我想在其中将函数存储为枚举类型
#[derive(Debug)]
enum RispErr {
Reason(String),
}
#[derive(Clone)]
enum RispExp {
Bool(bool),
Symbol(String),
Number(f64),
List(Vec<RispExp>),
Func(fn(&Vec<RispExp>) -> Result<RispExp, RispErr>),
}
在一种情况下,我想创建一个更高阶的函数来生成这些函数
// simplifying this for the question
// shortening this for brevity
fn make_tonicity_checker(
tone_fn: fn(f64, f64) -> bool,
) -> impl Fn(&Vec<RispExp>) -> Result<RispExp, RispErr> {
return move |args: &Vec<RispExp>| -> Result<RispExp, RispErr> {
tone_fn(1.0, 2.0); // need to use this
return Ok(RispExp::Bool(true));
};
}
尽管在尝试使用高阶函数时遇到错误
fn f() -> () {
RispExp::Func(make_tonicity_checker(|a, b| a > b));
}
mismatched types
expected fn pointer, found opaque type
note: expected type `for<'r> fn(&'r std::vec::Vec<RispExp>) -> std::result::Result<RispExp, RispErr>`
found type `impl for<'r> std::ops::Fn<(&'r std::vec::Vec<RispExp>,)>`rustc(E0308)
main.rs(93, 5): expected fn pointer, found opaque type
我更深入地研究并意识到,函数指针无法捕获环境,因此无法捕获错误。我尝试过
Func(Fn(&Vec<RispExp>) -> Result<RispExp, RispErr>),
但是意识到这也失败了,因为它在编译时没有已知的大小。进行了一些谷歌搜索,我发现我有可能将其作为类型参数传入
#[derive(Clone)]
enum RispExp<T>
where
T: Fn(&Vec<RispExp<T>>) -> Result<RispExp<T>, RispErr>,
{
Bool(bool),
Symbol(String),
Number(f64),
List(Vec<RispExp<T>>),
Func(T),
}
但是,在所有我接受RispExp
的地方,我都需要提供此类型参数。这似乎有点烦人,因为我将不得不在所有地方重复where T: Fn(&Vec<RispExp<T>>) -> Result<RispExp<T>, RispErr>,
。
我可以做Func(Box<Fn(&Vec<RispExp>) -> Result<RispExp, RispErr>>)
,但是dyn fn
没有实现克隆。
您会建议我做什么?谢谢您的帮助,从一开始的锈学习者开始:}
答案 0 :(得分:0)
如果要节省输入内容,请将您的type参数绑定为别名。
type RispFunc<T> = Fn(&Vec<RispExp<T>>) -> Result<RispExp<T>, RispErr>;
enum RispExp<Func: RispFunc<Func>> {
...
}
否则,如果您使用特征对象方法,则可以尝试实现自己的clone()
-How to clone a struct storing a boxed trait object?。