首页 文章

当自我被借入封闭内部时,使用静态生命周期触发“封闭可能会超过功能”

提问于
浏览
2

我的程序使用变量的内存地址作为唯一标识符 . 我知道这非常难看,但它是获取唯一标识符的一种非常轻量级的方法 . This pattern is only valid if I make these variables static so their unique id (i.e. address) lives "forever" 这意味着我有几个函数需要 'static 生命周期的引用 .

我正在使用cortex-m crate,它提供了一种方法,可以将处理器置于允许函数在无中断临界区运行的状态 . 这是通过一个函数来完成的,该函数将调用包装到需要在具有适当的程序集调用的关键部分中执行的函数 .

在这个人为的例子中,包装函数被称为 run_in_special_state . 我需要在特殊状态下执行 foo 方法 . 但是,它需要 'static Contrived . 这是一个说明错误的示例:

fn foo(_: &'static Contrived) {}

fn run_in_special_state<F, R>(f: F) -> R
where
    F: FnOnce() -> R,
{
    // Some stuff happens before the function
    let r = f();
    // Some stuff happens after the function
    r
}

struct Contrived {
    value: u32,
}

impl Contrived {
    fn func(&'static mut self) {
        run_in_special_state(|| foo(self));

        self.value = 6;
    }
}

static mut INSTANCE: Contrived = Contrived { value: 4 };

fn main() {
    unsafe { INSTANCE.func() };
}

这是你在操场上跑步时会得到的:

error[E0373]: closure may outlive the current function, but it borrows `self`, which is owned by the current function
  --> src/main.rs:19:30
   |
19 |         run_in_special_state(|| foo(self));
   |                              ^^     ---- `self` is borrowed here
   |                              |
   |                              may outlive borrowed value `self`
help: to force the closure to take ownership of `self` (and any other referenced variables), use the `move` keyword
   |
19 |         run_in_special_state(move || foo(self));
   |                              ^^^^^^^

我知道 FnOnce 将在 run_in_special_state 退出之前被调用 . 我相信这也意味着闭包不会比当前函数( func ?)更长,因为它(闭包)将在当前函数( func )退出之前被执行并被丢弃 . 如何与借阅检查员沟通?还有其他事情发生在这里吗?我注意到如果我在 foo 上删除 'static 要求,则错误消失 .

我不能做建议的修复,因为我需要在调用 run_in_special_state 之后使用 self .

1 回答

  • 1

    这些功能的签名:

    • fn foo(_: &'static Contrived)

    • fn func (&'static mut self)

    需要在整个程序期间借用其值的引用,而您需要的引用只需足够长的时间借用它们的值 .

    删除 'static ,程序将编译:

    fn foo(_: &Contrived) {}
    
    fn run_in_special_state<F, R>(f: F) -> R
    where
        F: FnOnce() -> R,
    {
        // Some stuff happens before the function
        let r = f();
        // Some stuff happens after the function
        r
    }
    
    struct Contrived {
        value: u32,
    }
    
    impl Contrived {
        fn func(&mut self) {
            run_in_special_state(|| foo(self));
    
            self.value = 6;
        }
    }
    
    static mut INSTANCE: Contrived = Contrived { value: 4 };
    
    fn main() {
        unsafe { INSTANCE.func() };
    }
    

    Playground

    &'static T isn 't just an address of a variable, it bears additional semantics. If you want to use it as a unique identifier, you' ll创建一个类型可能会更好,它只保留地址的唯一性并且不借用值:

    mod key {
        use super::Contrived;
    
        #[derive(Debug, Hash)]
        pub struct ContrivedId(usize);
    
        impl ContrivedId {
            pub fn new(r: &'static Contrived) -> Self {
                ContrivedId(r as *const _ as usize)
            }
        }
    }
    
    use key::ContrivedId;
    
    fn foo(_: ContrivedId) {}
    
    fn run_in_special_state<F, R>(f: F) -> R
    where
        F: FnOnce() -> R,
    {
        // Some stuff happens before the function
        let r = f();
        // Some stuff happens after the function
        r
    }
    
    pub struct Contrived {
        value: u32,
    }
    
    impl Contrived {
        fn func(&mut self, id: ContrivedId) {
            run_in_special_state(|| foo(id));
    
            self.value = 6;
        }
    }
    
    static mut INSTANCE: Contrived = Contrived { value: 4 };
    
    fn main() {
        unsafe {
            let id = ContrivedId::new(&INSTANCE);
            INSTANCE.func(id)
        };
    }
    

    Playground

相关问题