rust 你能把函数存储为结构体中的字段吗?如何存储指令?

68bkxrlz  于 2023-10-20  发布在  其他
关注(0)|答案(1)|浏览(116)

在我的模型中,我有一个Petgraph图,它将一个结构体存储为节点,其字段如下所示:

struct ControlBloc
{
    name:String,
    message_inbox:Vec<MessageObj>,
    blocked:bool,
    instruct:String,
    inbox_capacity:f64,
    buffer:Vec<MessageObj>,
    number_discarded:u32,
    clock_queue:SendingQueue,
    clock_speed:f64,
}

其中有一个名为instruct的字段,我想在其中存储指令。我想以一种方式对模型进行编码,以便在一段时间后,所有节点都将执行存储在结构中的指令。指令可以是例如发送消息到其他节点,计算的东西.我想要多功能的.
有没有一种方法可以将函数存储为结构中的字段?然后过一段时间后,可以调用存储的函数,然后执行任何函数?
我看到的一种方法是使用enum存储所有函数名,然后使用一个函数将任何枚举Map到相应的函数,例如:

enum FuncName {
    SendMessage,
    ComputeSize,
    StoreSomething,
    DoNothing,
}

fn exec_function(func:FuncName)
{
    match func {
        FuncName::SendMessage => send_message_function(input1,input2),
        FuncName::ComputeSize => compute_size_function(input1,input2,input3),
        FuncName::StoreSomething => store_something_funtion(input1),
        FuncName::DoNothing => (),
    }
}

然而,在这种情况下,你不能真正自定义FuncName函数的输入,它们要么必须总是预设为相同的东西,要么在exec_function的输入中添加FuncName中所有函数的所有不同输入字段,但这似乎有点过分,即使这样,我也不知道如何传递它们并存储在结构中。
那么有没有一种方法可以直接在结构中添加函数或其他东西呢?我知道我违反了很多Rust规则,但是比如说我已经声明了一个变量let bloc = ControlBloc::new(...);,那么你可以将函数设置为例如bloc.instruct = send_message_function(node1,node2);,然后当你调用bloc.instruct时,就会调用存储在那里的任何函数。
这样的事情可能吗?或者我在做梦,或者很难(我还在学习语言)?

taor4pac

taor4pac1#

你可以做的是将Box<dyn Fn()>存储在你的结构中:

struct Foo {
    instruct: Box<dyn Fn(Vec<i32>)>
}

fn sum(vec: Vec<i32>) {
    let sum: i32 = vec.into_iter().sum();
    println!("{}", sum);
}

fn main() {
    let foo = Foo {
        instruct: Box::new(|vec| {
            let sum: i32 = vec.into_iter().sum();
            println!("{}", sum);
        })
    };

    (foo.instruct)(vec![1, 2, 3, 4]);

    let foo = Foo {
        instruct: Box::new(sum)
    };

    (foo.instruct)(vec![1, 2, 3, 4]);
}

Fn是通过闭包自动实现的,闭包只接受对捕获变量的不可变引用,或者根本不捕获任何东西,以及(安全的)函数指针(有一些警告,请参阅其文档以了解更多细节)。此外,对于任何实现Fn的类型F,&F也实现Fn。

编辑

在我的示例中,我使用Vec<i32>作为多个参数的抽象。然而,如果你要有一些指令集,它们有不同的参数计数,但本身总是相同的,考虑创建一个trait Instruct,并为每个不同的指令创建结构体,以实现这一点。
Playground

struct Foo<T> {
    instruct: Box<dyn Instruct<T>>
}

trait Instruct<T> {
    fn run(&self) -> T;
}

struct CalcSum {
    f: Box<dyn Fn() -> i32>
}

impl CalcSum {
    fn new(arg: Vec<i32>) -> CalcSum {
        CalcSum {
            f: Box::new(move || arg.iter().sum::<i32>()),
        }
    }
}

impl Instruct<i32> for CalcSum {
    fn run(&self) -> i32 {
        (self.f)()
    }
}

相关问题