结构初始化取决于移动借用值

问题描述 投票:0回答:1

我正在尝试初始化如下结构:

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
的引用来更新它吗?

rust borrow-checker
1个回答
1
投票

由于

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
由于引用计数而引入了一些开销,因此请务必仅在必要时使用它。

© www.soinside.com 2019 - 2024. All rights reserved.