我目前正在为嵌入式板编写一个板支持包,并希望通过USB设置串行输出。我的设计基于hifive
BSP。
这个过程分为三个步骤:
- 设置USB总线(
UsbBusAllocator
,指的是一个UsbPeripheral
) - 初始化
SerialPort
实例,指UsbBusAllocator
- 初始化
UsbDevice
实例,它引用UsbBusAllocator
为了使我的生活更简单,我将SerialPort
和UsbDevice
包装在SerialWrapper
结构体中:
pub struct SerialWrapper<'a> {
port: SerialPort<'a, Usbd<UsbPeripheral<'a>>>,
dev: UsbDevice<'a, Usbd<UsbPeripheral<'a>>>,
}
impl<'a> SerialWrapper<'a> {
pub fn new(bus: &'a UsbPort<'a>) -> Self {
// create the wrapper ...
}
}
我想有一种方法使SerialWrapper::new
创建的结构全局
我尝试使用:
static mut STDOUT: Option<SerialWrapper<'a>> = None;
但是我不能使用这个,因为生命周期'a
没有声明。
我想使用MaybeUninit
或PhantomData
,但两者仍然需要将SerialWrapper<'a>
作为类型参数,我将得到同样的问题。
我的目标是能够使用类似这样的代码:
struct A;
struct B<'a> {
s: &'a A,
}
static mut STDOUT: Option<B> = None;
fn init_stdout() {
let a = A {};
unsafe {
STDOUT = Some(B {s: &a});
}
}
// access_stdout is the important function
// all the rest can be changed without issue
fn access_stdout() -> Result<(), ()> {
unsafe {
if let Some(_stdout) = STDOUT {
// do stuff is system ready
Ok(())
} else {
// do stuff is system not ready
Err(())
}
}
}
fn main() {
init_stdout();
let _ = access_stdout();
}
你对如何进行有什么建议吗?我不介意有一个需要不安全代码的解决方案,只要我能有安全的功能来访问我的串口。
简短的回答:当你在静态变量类型中有一个生命周期时,这个生命周期需要是'static
。
Rust不允许悬空引用,所以如果在静态变量中有任何比静态生命周期短的东西,就有可能存在悬空引用。我认为你的代码需要大量的重构来满足这个要求。我建议找到一种方法来存储不需要引用的数据,因为这将使您的工作更轻松。如果绝对必须存储引用,则需要找出一种方法来泄漏数据以将其生命周期延长到'static
。
我对嵌入式开发不是很熟悉,我知道static mut
在那里有一些用例,但是使用这个语言特性是非常普遍的。static mut
非常不安全,甚至通过允许同时使用多个可变引用来绕过一些借用检查器机制。如果要在Rust的类型系统中对其进行正确编码,您可能希望将其设置为static STDOUT: SyncWrapperForUnsafeCell<Option<T>>
,然后为包装器提供一个安全接口(可能涉及锁定),并提供注释,解释为什么当前环境使其安全。然而,如果你认为static mut
是合适的选择,我相信你的判断。