【问题标题】:How to dynamically build function calls with different numbers of arguments in Rust?如何在 Rust 中动态构建具有不同数量参数的函数调用?
【发布时间】:2019-07-02 16:07:33
【问题描述】:

如何获取函数参数 AST 变体的向量、提取值并使用它们来实例化函数调用?

我正在编写一个解释器来评估某些表达式。一些表达式是函数调用。我很难弄清楚如何将函数调用 AST 转换为实际调用。 AST 给了我函数名和参数向量。我可以使用映射从名称中查找要调用的函数指针,但是将参数传递给函数指针是有问题的。

Rust 没有 splat 运算符(参数扩展)。我可以将它们作为元组传递并使用参数的解构,但我不知道如何将 AST 参数枚举变量的向量转换为具体类型的元组。

我不能简单地映射或循环 AST 参数来提取值并生成一个元组。

我可以使用嵌套元组逐步构建异构列表:

fn prepend<I,T>(i: I, t: T) -> (I,T) { (i, t) }

fn foo() {
    let x = ();
    let x = prepend(1, x);
    let x = prepend(2.0, x);
    let x = prepend(true, x);
}

但这只是因为x 被遮蔽并且新绑定具有不同的类型。这行不通:

fn foo() {
    let mut x = ();
    x = prepend(1, x);
    x = prepend(2.0, x);
    x = prepend(true, x);
}

有什么想法吗?

【问题讨论】:

    标签: function dynamic rust interpreter


    【解决方案1】:

    你没有。 Rust 是一种 静态类型 语言,您正在尝试执行非静态可确定的操作。

    相反,您的所有函数都需要接收一组参数,验证参数数量是否正确(和类型,如果适合您的解释器),然后使用固定数量的参数调用适当的 Rust 函数:

    // All of the panicking can be replaced by proper error handling.
    
    enum Arg {
        Bool(bool),
        Int(i32),
    }
    
    impl Arg {
        fn into_bool(self) -> bool {
            match self {
                Arg::Bool(b) => b,
                _ => panic!("Not a bool"),
            }
        }
    
        fn into_int(self) -> i32 {
            match self {
                Arg::Int(i) => i,
                _ => panic!("Not an int"),
            }
        }
    }
    
    fn some_fn_wrapper(mut args: Vec<Arg>) {
        assert_eq!(args.len(), 3);
    
        let c = args.pop().unwrap();
        let b = args.pop().unwrap();
        let a = args.pop().unwrap();
    
        some_fn(a.into_bool(), b.into_int(), c.into_bool())
    }
    
    fn some_fn(_a: bool, _b: i32, _c: bool) {}
    

    所有这些都将在运行时发生,因为您想创建一种高度动态的语言。

    另见:

    【讨论】:

    • 感谢您的回复。事实上,除了将 AST 枚举变体的向量(例如 vec![Arg::Bool(true), Arg::Float(2.0), Arg::Int(1)]) 转换为异构值集合(例如 (true, 2.0, 1)(true, (2.0, (1,))) 来传递函数)的步骤之外,我可以做你建议的所有事情。我可以看看在映射中查找函数签名。我可以根据签名在不同映射中查找函数指针。我可以调用函数,最多支持一些支持的参数。但关键的一步是我卡住的地方。
    • 为什么不呢? Just write the code
    • 是的,您可以使用Vec&lt;Arg&gt; 并将其转换为元组。问题是如何通用地这样做,对于元组中可能的任何类型组合。例如,有许多具有不同签名类型的内置函数,一些取 (i32),一些 (i32, f64),一些 (&str, bool, i32) 等。给定一个Function(String,Vec&lt;Arg&gt;),如何一般取Vec&lt;Arg&gt; 并生成符合函数签名的元组或 HList。为参数类型和参数数量的所有可能组合实施类似do_it 的东西,直至达到一定限制,然后选择正确的?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-02
    • 2015-05-31
    • 1970-01-01
    • 1970-01-01
    • 2011-01-26
    • 1970-01-01
    相关资源
    最近更新 更多