rust - 当在闭包中借用 self 时,使用静态生命周期会触发 "closure may outlive function"

标签 rust borrow-checker

我的程序使用变量的内存地址作为唯一标识符。我知道这非常丑陋,但它是一种获取唯一标识符的非常轻量级的方法。 此模式仅在我将这些变量设为静态时有效,这样它们的唯一 ID(即地址)“永远”存在这意味着我有几个函数需要使用 '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() };
}

以下是您在 playground 中运行它时会得到的结果:

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

最佳答案

这些函数的签名:

  • 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 不仅仅是一个变量的地址,它还具有额外的语义。如果你想将它用作唯一标识符,你可能最好创建一个类型,它只保留地址的唯一性并且不借用值:

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

关于rust - 当在闭包中借用 self 时,使用静态生命周期会触发 "closure may outlive function",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48657718/

相关文章:

for-loop - 如何在 vector 的元素上运行 for 循环并更改 for 循环内部和 for 循环外部的向量?

rust - 从 HashMap 或 Vec 返回引用会导致借用超出其所在范围?

rust - 如何将 stderr 和 stdin 交错到 std::process::Command?

generics - 为两步从创建通用的“从/到”快捷方式

pointers - 什么是 "fat pointer"?

rust - Rust 的借用检查器是否使这个切片示例过于复杂?

rust - 在 Rust 中是否有惯用的方法来处理 "reference or create and use reference to it"模式?

url - Rust URL 删除特定的 GET 参数

rust - 为什么不能在同一结构中存储值和对该值的引用?

rust - 在其函数中捕获变量的结构体