我正在实现命令模式的实现,其中订阅者将从读取器线程接收数据,并且我在使用 Rust mocks 测试我的实现时遇到了问题。请考虑这个简化的示例:
use std::thread;
pub trait Subscriber: Sync + Send {
fn callback(&self);
}
pub struct Publisher {
thread_handler: Option<thread::JoinHandle<()>>,
}
impl Publisher {
pub fn new() -> Self {
Self {
thread_handler: None,
}
}
pub fn start(&mut self, sub: Box<dyn Subscriber>) {
self.thread_handler = Some(thread::spawn(move || {
sub.callback();
}));
}
}
#[cfg(test)]
mod tests {
use super::*;
use mockall::*;
mock! {
TestSubscriber {}
impl Subscriber for TestSubscriber {
fn callback(&self);
}
}
#[test]
fn test_subscriber() {
let mut publisher = Publisher::new();
let mut mock_test_subscriber = Box::new(MockTestSubscriber::new());
publisher.start(mock_test_subscriber);
mock_test_subscriber.expect_callback().times(1);
thread::sleep(std::time::Duration::from_millis(10));
}
}
这会引发
error[E0382]: borrow of moved value: `mock_test_subscriber`
--> src/foo.rs:46:9
|
42 | let mut mock_test_subscriber = Box::new(MockTestSubscriber::new());
| ------------------------ move occurs because `mock_test_subscriber` has type `Box<MockTestSubscriber>`, which does not implement the `Copy` trait
43 |
44 | publisher.start(mock_test_subscriber);
| -------------------- value moved here
45 |
46 | mock_test_subscriber.expect_callback().times(1);
| ^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
我真的不知道如何解决这个问题,我尝试过绕过它dyn Subscriber
,Arc
但仍然无法让它工作。任何建议都将不胜感激。或者也许有更好的设计来实现相同的结果。
尝试使用 是正确的
Arc
- 在执行临时多线程时,这应该是首先要尝试的。在这里,由于您尝试mock_test_subscriber
在两个线程之间共享,因此这正是您所需要的。因此,首先我们将 的签名更改为Publisher::start
使用Arc
:...并相应地更新呼叫站点:
请注意,我删除了
mut
on,mock_test_subscriber
因为它可能不是你的意思。写作let mut foo = Arc::new(T);
只是允许你设置foo
为另一个Arc
(即指向其他东西),而不是修改其底层值。在语义上是一个共享引用,因此由于Rust 对可变别名的规则而Arc
不能是可变的。从语法上讲,这表示为不实现。Arc
DerefMut
要获取对底层值的可变引用,请使用
Arc<Mutex<T>>
或Arc<RwLock<T>>
。Mutex
并且RwLock
能够通过在内部使用正确的同步原语来确保独占访问,从而通过共享引用安全地提供可变引用。