如何实例化基于闭包的类型

How to instantiate a type that is based on a closure

在我的项目中,我使用类型定义来保存具有特定函数签名的闭包,如下所示:

// Standardized function signature
pub type InternalOperation = impl Fn(Ast, Rc<RefCell<VTable>>, Rc<RefCell<FTable>>) -> Ctr;
pub struct ExternalOperation {
    // ...
    // The project is on gitlab called relish if you are interested
}

/* A stored function may either be a pointer to a function
 * or a syntax tree to eval with the arguments
 */
pub enum Operation {
    Internal(InternalOperation),
    External(ExternalOperation)
}

// function which does not need args checked
pub struct Function {
    pub function: Operation,
    // many more things like argument types and function name
}

我尝试实例化一个函数:

pub fn get_export(env_cfg: bool) -> Function {
    return Function{
        name: String::from("export"),
        loose_syms: true,
        eval_lazy: true,
        args: Args::Lazy(2),
        function: Operation::Internal(
            |a: Ast, b: Rc<RefCell<VTable>>, c: Rc<RefCell<FTable>>| -> Ctr {
                // so much logic here to manage variables in b
                // if env_cfg is true, entries in b are tied to environment variables 
        })
    }
}

但是我遇到了以下错误:

error[E0308]: mismatched types
  --> src/vars.rs:49:13
   |
49 | /             |a: Ast, b: Rc<RefCell<VTable>>, c: Rc<RefCell<FTable>>| -> Ctr {
50 | |                 let inner = a.borrow_mut();
51 | |                 match &inner.car {
52 | |                     Ctr::Symbol(identifier) => {
...  |
96 | |                 return Ctr::None;
97 | |             }
   | |_____________^ expected opaque type, found closure
   |

我尝试过的:

我在这里使用闭包,以便我的应用程序的用户配置可以在函数操作的主体内使用。是否可以以这种方式使用闭包,或者我是否需要重构我的代码以以其他方式应用 env_cfg 值?

我假设 type_alias_impl_trait 功能已打开。如果不是,则此代码无论如何都不应编译,因为没有此功能 impl Trait 不允许在类型别名中使用。


理论上,此功能应将类型别名的任何使用视为“定义用途”,即我们可以从中推断出不透明类型的用途。实际上,它(还)没有针对许多用途实施。据我所知,目前只有函数 return 类型被认为是定义用途。

但是,在您的情况下,您希望编译器从表达式中推断出类型。 它应该知道 Operation::Internal 的第一个字段是 InternalOperation 类型,因此 它应该知道 InternalOperationget_export()里面回调的类型。 理论上这应该可行,除非编译器(当前)不应用此知识。

您可以通过为 return 回调创建一个新函数来解决此问题:

fn get_callback(env_cfg: bool) -> InternalOperation {
    |a: Ast, b: Rc<RefCell<VTable>>, c: Rc<RefCell<FTable>>| -> Ctr {
        // so much logic here to manage variables in b
        // if env_cfg is true, entries in b are tied to environment variables
    }
}
pub fn get_export(env_cfg: bool) -> Function {
    Function {
        name: String::from("export"),
        loose_syms: true,
        eval_lazy: true,
        args: Args::Lazy(2),
        function: Operation::Internal(get_callback(env_cfg)),
    }
}