gpt4 book ai didi

rust - 在静态函数中使用 FnMut() 闭包

转载 作者:行者123 更新时间:2023-11-29 08:07:13 24 4
gpt4 key购买 nike

背景:我试图避免使用 Mutex/RefCell/Option在嵌入式系统的中断处理程序中跳舞。我不想使用堆(而且我不认为它应该是必要的——但随时告诉我错误)。我不能使用 std .我看过 cortex-m-rtfm它很整洁,但很有侵略性。无论如何,这是一种学习练习。如果可行,我更愿意使用闭包来处理中断,因为它感觉更接近于裸露的 Rust。我是一个彻头彻尾的 Rust 新手——我已经使用它大约一个星期了。在阅读文档、重读 Rust 书籍、博客文章等时,我尝试了很多不同的变体。我不知道我在这里做错了什么。

这是示例代码。要遵循的问题:

use core::cell::UnsafeCell;

pub struct Handler<'a> {
h: UnsafeCell<&'a dyn FnMut()>,
}

impl<'a> Handler<'a> {
pub fn new<T: FnMut()>(closure: &'a dyn FnMut()) -> Self {
Handler {
h: UnsafeCell::new(closure),
}
}

pub fn call(&self) {
unsafe {
// NOTE: type returned by `self.h.get()` is
// `*mut &'a (dyn std::ops::FnMut() + 'a)`
let h: *mut FnMut() = self.h.get();
h();
}
}
}
unsafe impl<'a> Sync for Handler<'a> {}

fn default_handler() {}

static HANDLER: Handler = Handler {
h: UnsafeCell::new(&default_handler),
};

#[test]
fn call_handler() {
let mut a: u32 = 0;
let foo = move || a += 1;
let mut handler = Handler::new(&foo);
handler.call();
a += 2; // Shouldn't this cause compilation failure because `a`
// was moved into the closure above?
assert_eq!(a, 1);
}

错误

error[E0618]: expected function, found `*mut dyn std::ops::FnMut()`
--> src/lib.rs:19:13
|
18 | let h: *mut FnMut() = self.h.get();
| - `*mut dyn std::ops::FnMut()` defined here
19 | h();
| ^--
| |
| call expression requires function

error[E0277]: expected a `std::ops::Fn<()>` closure, found `(dyn std::ops::FnMut() + 'a)`
--> src/lib.rs:18:35
|
18 | let h: *mut FnMut() = self.h.get();
| ^^^^^^^^^^^^ expected an `Fn<()>` closure, found `(dyn std::ops::FnMut() + 'a)`
|
= help: the trait `std::ops::Fn<()>` is not implemented for `(dyn std::ops::FnMut() + 'a)`
= note: wrap the `(dyn std::ops::FnMut() + 'a)` in a closure with no arguments: `|| { /* code */ }
= note: required because of the requirements on the impl of `std::ops::FnMut<()>` for `&'a (dyn std::ops::FnMut() + 'a)`
= note: required for the cast to the object type `dyn std::ops::FnMut()`

解释:希望我的意图很明显:我将为 HANDLER 设置闭包。在main ,在进入永不退出的繁忙循环之前。闭包将可变地借用中断处理程序运行所需的东西,防止它在其他上下文中使用。自 main永远不会退出,其中的堆栈分配变量实际上是 'static ,因此在设置闭包后的任何时候引用它们都不会有问题。中断处理程序本身(未显示)将简单地调用闭包来完成它的工作。要在静态中解决闭包(不是 Sized)的存储问题,我需要存储对闭包的引用。 UnsafeCell不一定是必需的,但因为我正在使用 FnMut()它的引用对象需要是可变的,这会遇到 statics require immutable values尝试设置 default_handler 时在创建 static mut HANDLER 的过程中.

问题:

  1. 正如发布的那样,此代码无法编译。由于某种原因,作业 let h: *mut FnMut() = self.h.get()告诉我它
    expected an Fn<()> closure, found (dyn std::ops::FnMut() + 'a)
    .好吧,我知道为什么它会找到那种类型。但为什么它期待 Fn<()> ?

  2. call_handler测试,为什么要编译? foo关闭move这是它捕获的变量 a .在闭包定义之后如何改变它?当我使用未实现 Copy 的类型尝试此代码时,它按预期失败了,但坦率地说,我很惊讶特质很重要。 foo 不是重点吗?拥有a现在?

我意识到更改 HANDLER.h 存在潜在问题在代码中的任意点,但我会担心在有可行的概念验证之后解决这些问题。

最佳答案

我找到了一种方法来做我想做的事。它对于一般用途来说是非常不安全的,必须研究隐藏其缺乏安全性的适当机制,甚至可能是不可能的。主要技巧是使用 as 转换将可变特征对象转换为动态对象,并使用 core::mem::transmute 将其生命周期更改为 静态。这是代码:

use core::cell::UnsafeCell;
use core::mem::transmute;

struct Handler {
h: UnsafeCell<*const dyn FnMut()>,
}

impl Handler {
unsafe fn replace(&self, f: &dyn FnMut()) {
let f_static: &'static dyn FnMut() = transmute(f);
*self.h.get() = f_static;
}

unsafe fn call(&self) {
let f: &mut dyn FnMut() = &mut *(*self.h.get() as *mut dyn FnMut());
f();
}
}
unsafe impl Sync for Handler {}

fn default_handler() {}
static HANDLER: Handler = Handler {
h: UnsafeCell::new(&default_handler),
};

fn main() {
let mut x: u32 = 0;
let closure = || x += 2;

unsafe {
HANDLER.replace(&closure);
HANDLER.call();
};
println!("x: {}", x); // Prints 2
}

Handler.h 包裹的闭包位于 UnsafeCell 中,以便于在运行时(在且仅在主循环内部)替换它。

关于rust - 在静态函数中使用 FnMut() 闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55818993/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com