简体   繁体   中英

Rust lifetimes when closure created by struct method takes a mutable referece to that struct

I am new to rust, and especially to embedded rust. I have written something which maintains an 'alarm system', which can be in a variety of defined states. The Alarm struct, when transitioning to the armed state, sets up a GPIO pin interrupt with a closure that should be able to set the alarm's state to Alarm when triggered. The compiler complains that there is no guarantee that the closure will not outlive the struct. I understand the issue, but I am not clear on how to fix it.

use crate::pins::CustomPin;
use sysfs_gpio::Pin;
#[derive(Debug)]
pub enum States {
    Disarmed,
    Armed,
    Alarm,
    Error,
}
pub struct Alarm {
    pub state: States,
    pub trigger_pin: Pin,
}
impl Alarm {
    pub fn arm(&mut self) -> () { // `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
        match self.trigger_pin.set_interrupt(Box::new(|| self.trigger())) { //...is captured and required to live as long as `'static` here
            Ok(_) => self.update(States::Armed),
            Err(_) => self.update(States::Error),
        };
    }
    pub fn disarm(&mut self) -> () {
        self.update(States::Disarmed);
    }
    pub fn trigger(&mut self) -> () {
        self.update(States::Alarm);
    }
    pub fn new(trigger_pin: u64) -> Alarm {
        let input = Pin::new(trigger_pin);
        Alarm {
            state: States::Disarmed,
            trigger_pin: input,
        }
    }
    fn update(&mut self, state: States) -> () {
        self.state = state;
    }
}

--

extern crate sysfs_gpio;
use sysfs_gpio::{Direction, Edge, Pin};
pub trait CustomPin {
    fn set_interrupt(&self, callback: Box<dyn Fn() -> ()>) -> sysfs_gpio::Result<()>;
}
impl CustomPin for Pin {
    fn set_interrupt(&self, callback: Box<dyn Fn() -> ()>) -> sysfs_gpio::Result<()> {
        self.with_exported(|| {
            self.set_direction(Direction::In)?;
            self.set_edge(Edge::FallingEdge)?;
            let mut poller = self.get_poller()?;
            loop {
                match poller.poll(1000)? {
                    Some(_) => callback(),
                    None => (),
                }
            }
        })
    }
}

I understand the compiler message, but I don't know how to fix it. I considered a RefCell , but my understanding is that this would force the Alarm to live for as long as the closure, when in fact, the closure should not outlive the Alarm.

I suppose the point fundamentally is that I don't know how to drop that closure explicitly.

Your problem is that Box assumes a static lifetime unless explicitly stated otherwise. Consequently, the lifetime problem in your example can be fixed by defining an explicit lifetime parameter to the trait like:

pub trait CustomPin {
    fn set_interrupt<'a>(&self, callback: Box<dyn FnMut() -> () + 'a>) -> sysfs_gpio::Result<()>;
}

Unfortunately, there are more fundamental ownership issues in your example that the borrow checker will reject. Your essential problem is that you're referencing self from every closure, especially even from functions requiring &mut self . This will always fail, you need an Rc or similar constructs to reference the same Alarm struct from multiple places following the "average C++ construct" you're probably migrating from.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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