如何编写接受特征或指向特征的智能指针(Box、Rc 等)的通用代码?
How do I write generic code that accepts either a trait or a smart pointer to the trait (Box, Rc, etc)?
我正在编写一个模拟流程、交换事件的离散事件模拟器。流程是特征流程的实现,并存储在模拟 class 中,它告诉它们何时处理事件。
一个模拟可以只包含一种类型的进程,也可以包含不同类型的进程。这就是为什么我需要能够自由选择动态进程的原因。
我目前用盒子来做。每个使用模拟的代码都需要创建盒子并将其创建的对象放入盒子中。
trait Process {
// methods
fn start();
fn process_event();
}
struct Simulation {
processes: Vec<dyn Process>
}
impl Simulation {
fn add_process(&mut self, p: Box<dyn Process>) {
processes.push(p);
}
fn run() {
// calls process_event on processes, based on simulation logic
}
}
我最大的问题是,在某些情况下,这些进程需要有自引用。然后我需要用 Pin 或 OwningRef 替换 box,我不想进行所有可能的模拟,创建 Pin 或 OwningRef。所以,我想要某种通用参数来告诉模拟对框使用不同的 classes。
一个很好的扩展是完全没有动态调度,并且模拟包含实际的流程类型,而不是泛型。
所以,我想要 - Simulation<P> where P is either a Process or Deref<Process>
.
通用 Simulation
的两种变体都是可能的。
- 包含指向进程的智能指针(playground):
trait Process {}
struct P {}
impl Process for P {}
struct Simulation<T: std::ops::Deref<Target = dyn Process> + Sized> {
processes: Vec<T>
}
impl<T: std::ops::Deref<Target = dyn Process> + Sized> Simulation<T> {
fn add_process(&mut self, p: T) {
self.processes.push(p);
}
fn run(&self) {
// calls process_event on processes, based on simulation logic
}
}
fn main() {
let mut s: Simulation<Box<dyn Process>> = Simulation { processes: vec![] };
s.add_process(Box::new(P {}));
s.run();
let mut s: Simulation<std::rc::Rc<dyn Process>> = Simulation { processes: vec![] };
s.add_process(std::rc::Rc::new(P {}));
s.run();
}
- 包含实际进程类型(playground):
trait Process {}
struct P {}
impl Process for P {}
struct P2 {}
impl Process for P2 {}
struct Simulation<T: Process> {
processes: Vec<T>
}
impl<T: Process> Simulation<T> {
fn add_process(&mut self, p: T) {
self.processes.push(p);
}
fn run(&self) {
// calls process_event on processes, based on simulation logic
}
}
fn main() {
let mut s: Simulation<P> = Simulation { processes: vec![] };
s.add_process(P {});
s.run();
let mut s: Simulation<P2> = Simulation { processes: vec![] };
s.add_process(P2 {});
s.run();
}
- 您甚至可以拥有一种类型的模拟,其中包含不同类型的流程 (playground):
trait Process {}
struct P {}
impl Process for P {}
struct P2 {}
impl Process for P2 {}
struct Simulation {
processes: Vec<Box<dyn Process>>
}
impl Simulation {
fn add_process<T: Process + 'static>(&mut self, p: T) {
self.processes.push(Box::new(p));
}
fn run(&self) {
// calls process_event on processes, based on simulation logic
}
}
fn main() {
let mut s: Simulation = Simulation { processes: vec![] };
s.add_process(P {});
s.run();
let mut s: Simulation = Simulation { processes: vec![] };
s.add_process(P2 {});
s.run();
}
我正在编写一个模拟流程、交换事件的离散事件模拟器。流程是特征流程的实现,并存储在模拟 class 中,它告诉它们何时处理事件。
一个模拟可以只包含一种类型的进程,也可以包含不同类型的进程。这就是为什么我需要能够自由选择动态进程的原因。
我目前用盒子来做。每个使用模拟的代码都需要创建盒子并将其创建的对象放入盒子中。
trait Process {
// methods
fn start();
fn process_event();
}
struct Simulation {
processes: Vec<dyn Process>
}
impl Simulation {
fn add_process(&mut self, p: Box<dyn Process>) {
processes.push(p);
}
fn run() {
// calls process_event on processes, based on simulation logic
}
}
我最大的问题是,在某些情况下,这些进程需要有自引用。然后我需要用 Pin 或 OwningRef 替换 box,我不想进行所有可能的模拟,创建 Pin 或 OwningRef。所以,我想要某种通用参数来告诉模拟对框使用不同的 classes。
一个很好的扩展是完全没有动态调度,并且模拟包含实际的流程类型,而不是泛型。
所以,我想要 - Simulation<P> where P is either a Process or Deref<Process>
.
通用 Simulation
的两种变体都是可能的。
- 包含指向进程的智能指针(playground):
trait Process {}
struct P {}
impl Process for P {}
struct Simulation<T: std::ops::Deref<Target = dyn Process> + Sized> {
processes: Vec<T>
}
impl<T: std::ops::Deref<Target = dyn Process> + Sized> Simulation<T> {
fn add_process(&mut self, p: T) {
self.processes.push(p);
}
fn run(&self) {
// calls process_event on processes, based on simulation logic
}
}
fn main() {
let mut s: Simulation<Box<dyn Process>> = Simulation { processes: vec![] };
s.add_process(Box::new(P {}));
s.run();
let mut s: Simulation<std::rc::Rc<dyn Process>> = Simulation { processes: vec![] };
s.add_process(std::rc::Rc::new(P {}));
s.run();
}
- 包含实际进程类型(playground):
trait Process {}
struct P {}
impl Process for P {}
struct P2 {}
impl Process for P2 {}
struct Simulation<T: Process> {
processes: Vec<T>
}
impl<T: Process> Simulation<T> {
fn add_process(&mut self, p: T) {
self.processes.push(p);
}
fn run(&self) {
// calls process_event on processes, based on simulation logic
}
}
fn main() {
let mut s: Simulation<P> = Simulation { processes: vec![] };
s.add_process(P {});
s.run();
let mut s: Simulation<P2> = Simulation { processes: vec![] };
s.add_process(P2 {});
s.run();
}
- 您甚至可以拥有一种类型的模拟,其中包含不同类型的流程 (playground):
trait Process {}
struct P {}
impl Process for P {}
struct P2 {}
impl Process for P2 {}
struct Simulation {
processes: Vec<Box<dyn Process>>
}
impl Simulation {
fn add_process<T: Process + 'static>(&mut self, p: T) {
self.processes.push(Box::new(p));
}
fn run(&self) {
// calls process_event on processes, based on simulation logic
}
}
fn main() {
let mut s: Simulation = Simulation { processes: vec![] };
s.add_process(P {});
s.run();
let mut s: Simulation = Simulation { processes: vec![] };
s.add_process(P2 {});
s.run();
}