繁体   English   中英

如何将具体的静态分派的“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>>>

我已经看到(看起来像)这种模式在许多情况下使用,但我无法说出我错过了什么或做了不同的事情。

如何从其 static 调度中获取T: Trait并进入动态调度?

您可以在wrap function 之外进行装箱,并使用正确的盒子类型将柜台本身装箱:


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指向具体类型的指针。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM