我有一个用例,希望将函数存储为枚举类型

#[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没有实现Clone
你会推荐我做什么?

最佳答案

如果您想节省键入的时间,请将您的type参数绑定(bind)为别名。

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?

关于rust - 如何以枚举类型存储impl Fn?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55758511/

10-13 07:45