如何在Rust中动态构建具有不同数量参数的函数调用? [英] How to dynamically build function calls with different numbers of arguments in Rust?

查看:83
本文介绍了如何在Rust中动态构建具有不同数量参数的函数调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

How do I take a vector of function argument AST variants, extract the values, and use them to instantiate a function call?

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

I am writing an interpreter that evaluates certain expressions. Some of the expressions are function calls. I am having a hard time figuring out how to translate the function calls AST to the actual call. The AST gives me the function name and a vector of arguments. I can lookup the function pointer to call from the name using a map, but passing the arguments to the function pointer is problem.

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

Rust does not have a splat operator (argument expansion). I could pass them as a tuple and use destructuring of the arguments, but I can't figure out how to convert the vector of AST argument enum variants to a tuple of the concrete types.

我不能简单地映射或循环AST参数以提取值并生成元组.

I can't simply map or loop over the AST arguments to extract the values and produce a tuple.

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

I can use nested tuples to build a heterogenous list incrementally:

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 会被遮盖并且新的绑定具有不同的类型.这是行不通的:

But that only works because x gets shadowed and the new binding has a different type. This won't work:

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

有什么想法吗?

推荐答案

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

You don't. Rust is a statically typed language and you are attempting to do non-statically-determinable actions.

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

Instead, all of your functions need to take in a collection of arguments, verify that there is the right number of arguments (and type, if appropriate to your interpreter), then call the appropriate Rust function with a fixed number of arguments:

// 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) {}

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

All of this will happen at runtime, as you want to create a highly dynamic language.

另请参阅:

这篇关于如何在Rust中动态构建具有不同数量参数的函数调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆