我正在尝试初始化如下结构:
struct UsbCommandPort<'a> {
serial: SerialPort<'a, UsbBus<USB>>,
usb_dev: UsbDevice<'a, UsbBus<USB>>,
}
impl UsbCommandPort<'_> {
pub fn new() -> Self
{
let usb: USB = USB::new();
let usb_bus: UsbBusAllocator<UsbBus<USB>> = UsbBus::new(usb);
let serial:SerialPort<'_, UsbBus<USB>> = SerialPort::new(&usb_bus);
let usb_dev:UsbDevice<'_, UsbBus<USB>> = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd))
.device_class(usbd_serial::USB_CLASS_CDC)
.build();
UsbCommandPort {
serial: serial,
usb_dev: usb_dev,
}
}
SerialPort::new
和UsbDeviceBuilder::new
都对usb_bus
进行参考。
此函数无法编译并出现错误
error[E0515]: cannot return value referencing local variable `usb_bus`
这是有道理的,因为当函数返回时,
usb_bus
将不再存在,并且引用将悬空。
为了防止这种情况发生,我想将
usb_bus
的所有权转移到结构体。所以我将它添加为成员变量:
struct UsbCommandPort<'a> {
usb_bus: UsbBusAllocator<UsbBus<USB>>,
serial: SerialPort<'a, UsbBus<USB>>,
usb_dev: UsbDevice<'a, UsbBus<USB>>,
}
impl UsbCommandPort<'_> {
pub fn new() -> Self
{
let usb: USB = USB::new();
let usb_bus: UsbBusAllocator<UsbBus<USB>> = UsbBus::new(usb);
let serial:SerialPort<'_, UsbBus<USB>> = SerialPort::new(&usb_bus);
let usb_dev:UsbDevice<'_, UsbBus<USB>> = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd))
.device_class(usbd_serial::USB_CLASS_CDC)
.build();
UsbCommandPort {
usb_bus: usb_bus,
serial: serial,
usb_dev: usb_dev,
}
}
但是这也无法编译。之前的错误仍然存在:
error[E0515]: cannot return value referencing local variable `usb_bus`
现在出现了一个新错误:
error[E0505]: cannot move out of `usb_bus` because it is borrowed
我无法将
usb_bus
的所有权转移到该结构,因为它已经被借用了。但是,如果不初始化需要借用的 serial
和 usb_dev
,我无法创建结构。
我可以通过首先分配
usb_bus
来逐步初始化该结构,然后通过分配 serial
和 usb_dev
以及对结构拥有的 usb_bus
的引用来更新它吗?
由于
serial
和 usb_dev
都引用了 usb_bus
,Rust 的借用检查器会阻止您按照您尝试的方式构建代码。
但是,您可以使用 Rust 的所有权模型来解决这个问题。一种方法是使用
Rc
或 Arc
来启用结构体中 usb_bus
的多重所有权。您可以通过以下方式修改代码来实现此目的:
use std::sync::Arc;
struct UsbCommandPort<'a> {
usb_bus: Arc<UsbBusAllocator<UsbBus<USB>>>,
serial: SerialPort<'a, UsbBus<USB>>,
usb_dev: UsbDevice<'a, UsbBus<USB>>,
}
impl UsbCommandPort<'_> {
pub fn new() -> Self {
let usb: USB = USB::new();
let usb_bus: Arc<UsbBusAllocator<UsbBus<USB>>> = Arc::new(UsbBus::new(usb));
let serial: SerialPort<'_, UsbBus<USB>> = SerialPort::new(&usb_bus);
let usb_dev: UsbDevice<'_, UsbBus<USB>> = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd))
.device_class(usbd_serial::USB_CLASS_CDC)
.build();
UsbCommandPort {
usb_bus: usb_bus.clone(),
serial,
usb_dev,
}
}
}
通过将
usb_bus
包装在 Arc
中,您可以启用多重所有权。 clone()
上的Arc
方法用于创建新的引用,该引用将在serial
和usb_dev
中使用。这样,与借款相关的所有权问题就应该得到解决。请记住,Arc
由于引用计数而引入了一些开销,因此请务必仅在必要时使用它。