如何将具体的、静态调度的“T: Trait”转换为动态调度的“dyn Trait”?
How do I convert a concrete, statically dispatched `T: Trait` to a dynamically dispatched `dyn Trait`?
在这段代码中,我有一个可观察系统的骨架。关于实现 Observable 和其他解耦模式的文档通常缺少允许访问侦听器的最后一步,同时在通知调用期间也将其设为 &mut
,但这正是 RefCell
旨在处理的内容。所以我已经完成了这段代码,但是我在将我的具体 T
放入 &dyn Trait
.
中遇到了最后的麻烦
use std::{cell::RefCell, rc::Rc};
pub trait Observer {
fn notify(&mut self);
}
#[derive(Default)]
pub struct Subject<'s> {
listeners: Vec<Rc<RefCell<Box<dyn Observer + 's>>>>,
}
pub fn wrap<T>(t: T) -> Rc<RefCell<Box<T>>> {
Rc::new(RefCell::new(Box::new(t)))
}
impl<'s> Subject<'s> {
pub fn add_observer(&mut self, observer: Rc<RefCell<Box<dyn Observer + 's>>>) {
self.listeners.push(observer)
}
pub fn notify(&mut self) {
for listener in &mut self.listeners {
listener.borrow_mut().notify();
}
}
}
#[cfg(test)]
mod test {
use super::{wrap, Observer, Subject};
#[derive(Default)]
pub struct Counter {
count: usize,
}
impl Observer for Counter {
fn notify(&mut self) {
self.count += 1;
}
}
#[test]
fn it_observes() {
let mut subject = Subject::default();
let counter = wrap(Counter::default());
subject.add_observer(counter); // mismatched types
for i in 1..5 {
subject.notify();
subject.notify();
assert_eq!(counter.borrow().count, i * 2);
}
}
}
完整的错误是
error[E0308]: mismatched types
--> src/observer.rs:48:30
|
48 | subject.add_observer(counter);
| ^^^^^^^ expected trait object `dyn Observer`, found struct `Counter`
|
= note: expected struct `Rc<RefCell<Box<(dyn Observer + 'static)>>>`
found struct `Rc<RefCell<Box<Counter>>>
我已经看到(看起来像)这种模式在许多情况下使用,但我不知道我遗漏了什么或做了什么不同的事情。
如何让 T: Trait
脱离静态调度并进入动态调度?
您可以在 wrap
函数之外进行装箱,并使用适当的框类型对计数器本身进行装箱:
pub fn wrap<T>(t: T) -> Rc<RefCell<T>> {
Rc::new(RefCell::new(t))
}
...
let counter: Box<dyn Observer> = Box::new(Counter::default());
let counter = wrap(counter);
顺便说一句,一旦你有了动态调度,你就有了一个 dyn Observer
所以你无法访问 Counter
本身。您将必须再次取得它的所有权,downcast
指向具体类型的指针。
在这段代码中,我有一个可观察系统的骨架。关于实现 Observable 和其他解耦模式的文档通常缺少允许访问侦听器的最后一步,同时在通知调用期间也将其设为 &mut
,但这正是 RefCell
旨在处理的内容。所以我已经完成了这段代码,但是我在将我的具体 T
放入 &dyn Trait
.
use std::{cell::RefCell, rc::Rc};
pub trait Observer {
fn notify(&mut self);
}
#[derive(Default)]
pub struct Subject<'s> {
listeners: Vec<Rc<RefCell<Box<dyn Observer + 's>>>>,
}
pub fn wrap<T>(t: T) -> Rc<RefCell<Box<T>>> {
Rc::new(RefCell::new(Box::new(t)))
}
impl<'s> Subject<'s> {
pub fn add_observer(&mut self, observer: Rc<RefCell<Box<dyn Observer + 's>>>) {
self.listeners.push(observer)
}
pub fn notify(&mut self) {
for listener in &mut self.listeners {
listener.borrow_mut().notify();
}
}
}
#[cfg(test)]
mod test {
use super::{wrap, Observer, Subject};
#[derive(Default)]
pub struct Counter {
count: usize,
}
impl Observer for Counter {
fn notify(&mut self) {
self.count += 1;
}
}
#[test]
fn it_observes() {
let mut subject = Subject::default();
let counter = wrap(Counter::default());
subject.add_observer(counter); // mismatched types
for i in 1..5 {
subject.notify();
subject.notify();
assert_eq!(counter.borrow().count, i * 2);
}
}
}
完整的错误是
error[E0308]: mismatched types
--> src/observer.rs:48:30
|
48 | subject.add_observer(counter);
| ^^^^^^^ expected trait object `dyn Observer`, found struct `Counter`
|
= note: expected struct `Rc<RefCell<Box<(dyn Observer + 'static)>>>`
found struct `Rc<RefCell<Box<Counter>>>
我已经看到(看起来像)这种模式在许多情况下使用,但我不知道我遗漏了什么或做了什么不同的事情。
如何让 T: Trait
脱离静态调度并进入动态调度?
您可以在 wrap
函数之外进行装箱,并使用适当的框类型对计数器本身进行装箱:
pub fn wrap<T>(t: T) -> Rc<RefCell<T>> {
Rc::new(RefCell::new(t))
}
...
let counter: Box<dyn Observer> = Box::new(Counter::default());
let counter = wrap(counter);
顺便说一句,一旦你有了动态调度,你就有了一个 dyn Observer
所以你无法访问 Counter
本身。您将必须再次取得它的所有权,downcast
指向具体类型的指针。