我试图创建一个结构体,使能一个引脚,然后在一段时间后禁用它。我遇到了一个所有权问题,我不太确定如何解决它。
下面是我正在使用的代码:
pub trait PumpPin {
fn enable(self);
fn disable(self);
}
impl PumpPin for Gpio4<Output> {
fn enable(mut self: Gpio4<Output>) {
self.set_high().unwrap();
}
fn disable(mut self: Gpio4<Output>) {
self.set_low().unwrap();
}
}
pub struct PumpManager<T: PumpPin + std::marker::Send + 'static + std::marker::Sync> {
pin: T,
}
impl<T: PumpPin + std::marker::Send + 'static + std::marker::Sync> PumpManager<T> {
pub fn new(pin: T) -> PumpManager<T> {
PumpManager { pin }
}
pub fn run_pump(self, time: u64) -> Result<(), EspError> {
self.pin.enable();
// Configure the timer to disable the pin
let once_timer = EspTimerService::new()
.unwrap()
.timer(move || self.pin.disable());
//actually set a time for the timer
once_timer.unwrap().after(Duration::from_secs(time))
}
}
我的目标是封装所有处理泵定时的逻辑。
下面的错误位于self.pin.disable()
cannot move out of `self.pin`, as `self` is a captured variable in an `FnMut` closure
move occurs because `self.pin` has type `T`, which does not implement the `Copy` trait
我以为pin的所有权属于PumpManager
本身,但实际上它属于调用它的任何函数。有没有方法可以重构它来完成我想做的事情?
1条答案
按热度按时间wr98u20j1#
你的直觉几乎是正确的:
pin
由PumpManager
拥有,但是PumpManager
由run_pump()
拥有,因为该方法通过self
取得所有权。这里有一个共同的期望:
PumpPin::disable()
通过self
获得所有权,但是esp_idf_svc::timer::EspTimerService::timer()
需要FnMut()
,也就是说,它需要可以多次调用的闭包但是我们不能把self.pin
的所有权移入闭包,通过pin.disable()
把pin
移出闭包,并再次调用闭包-因为pin
到那时已经不存在了。这就是为什么FnMut
的需求没有得到满足的原因。EspTimerService::timer()
强制一个闭包,它可以从周期性计时器调用,而PumpPin::disable()
强制它只能被调用一次,但它可以从一个周期性计时器调用;有人可能会说esp_idf_svc
-API的设计很糟糕,但事实就是如此。*如果你可以将
PumpPin::disable()
更改为不获取所有权(但是,例如&mut self
),那么你的闭包就可以变成FnMut
。如果你不能改变
PumpPin::disable()
,你可以把self.pin
移到一个Option
中,把.take()
移到闭包中那个Option
之外的pin
中。(计时器执行的唯一时间),如果计时器多次触发(虽然不会发生,但就编译器而言,它是正确的),则会在此后返回None
。例如: