首页 > 解决方案 > 我可以序列化 Vec 的闭包吗然后反序列化并执行它?

问题描述

我想做这样的伪代码:

let mut vec = Vec<u8>::new();
vec.resize(1024); // Some large-enough size

serialize(&vec, || { .... });

// ... other code blah blah ...

deserialize(&vec); // This will execute the closure

理想情况下,我将能够在另一个线程中运行反序列化,这就是这样做的真正意义所在。

我不想发送操作码和数据,因为这种方式打开了一个非常干净的编程模型,您无需创建消息并发送它们。相反,您只需在另一个线程中运行任意复杂的代码。

为什么“非常干净”?

  1. 没有需要创建的操作码(消息)。即,更少的代码。

  2. 接收端没有用于操作码调度的 switch 语句。即,更少的代码。

  3. 由于没有协议,因此无需对消息进行版本控制。即,更少的代码。

这个想法不能跨进程使用,但这对我的需要来说是可以的。

标签: serializationrustclosures

解决方案


不使用unsafe? 不不不不。

问题是,由于Vec<u8>s 可以被简单地修改,你很容易违反 Rust 的安全不变量。考虑以下代码:

let vec = Vec<u8>::new();
vec.resize(1024);
// Our theoretical serialize function.
serialize(&vec, || { /* ... */ });
vec[0] = 0x90; // What happens to the closure now?
deserialize(&vec); // There goes any memory safety...

但是,如果您只想在线程之间发送闭包,请考虑使用类似的东西std::sync::mpsc,它支持发送闭包:

use std::thread;
use std::sync::mpsc::channel;

let (tx, rx) = channel();
thread::spawn(move || {
    tx.send(|| { "hi" }).unwrap();
});
let f = rx.recv().unwrap();
assert_eq!(f(), "hi");

但是,我的猜测是,这实际上不是您想要做的。就像 Netwave 在评论中所说的那样,您很可能实际上想要发送数据和操作的标签;例如:

// On one thread...
tx.send((Op::REMOVE_FILE, path));
// and on the other thread...
let (op, path) = rx.recv();
match op {
  Op::REMOVE_FILE => remove_file(path),
  /* ... */
}

推荐阅读