首页 > 解决方案 > 从函数返回 libusb::Device 的问题 - 尝试返回引用当前函数拥有的数据的值

问题描述

我想与 USB 设备连接,所以我使用libusb。我有一个函数可以返回libusb::Device我感兴趣的设备:

pub fn obtain_device() -> Device<'static> {
    let context: Context = libusb::Context::new().unwrap();
    let option: Device = context
        .devices()
        .unwrap()
        .iter()
        .find(|d| d.device_descriptor().unwrap().vendor_id() == 0x0bda)
        .unwrap();
    option
}

但是,这不会编译:

error[E0515]: cannot return value referencing local variable `context`
  --> src/usb/mod.rs:19:5
   |
18 |     let option: Device = context.devices().unwrap().iter().find(|d| d.device_descriptor().unwrap().vendor_id() == 0x0bda).unwrap();
   |                          ------- `context` is borrowed here
19 |     option
   |     ^^^^^^ returns a value referencing data owned by the current function

在我的理解中context,它是导致问题的对象,即使这不是我从函数返回的对象。看定义libusb::Device

/// A reference to a USB device.
pub struct Device<'a> {
    context: PhantomData<&'a Context>,
    device: *mut libusb_device,
}

它包含对 a 的引用Context,我认为这是编译失败的原因。但是我不确定如何Device从函数中返回 a ,或者我没有正确思考应该如何编码。如果我想将Device对象传递给其他函数怎么办?

标签: rustborrowing

解决方案


根据 的定义Context::devices,生命周期'ainDevice<'a>绑定到上下文的范围,如果Context超出范围将变为无效(即,将是一个悬空指针)。也就是说,箱子不只是包装一些指向将永远存在的设备的指针,而是“通过”上下文访问设备。

处理这个问题的一种方法是制作Context静态的,所以它在你的程序的整个持续时间内都存在。你可以这样做lazy_static

use lazy_static::lazy_static;
use libusb::{Context, Device};

lazy_static! {
    static ref CONTEXT: Context = Context::new().unwrap();
}

pub fn obtain_device() -> Device<'static> {
    CONTEXT
        .devices()
        .unwrap()
        .iter()
        .find(|d| d.device_descriptor().unwrap().vendor_id() == 0x0bda)
        .unwrap()
}

你也可以把你的函数变成一个结构的方法,它拥有Context.

pub struct MyDeviceContext {
    context: libusb::Context,
}

impl MyDeviceContext {
    pub fn new(context: libusb::Context) -> Self {
        Self { context }
    }

    pub fn obtain_device(&self) -> Device<'_> {
        self.context
            .devices()
            .unwrap()
            .iter()
            .find(|d| d.device_descriptor().unwrap().vendor_id() == 0x0bda)
            .unwrap()
    }
}

设备生命周期不再是'static,但只要MyDeviceContext仍在范围内就可以使用。


推荐阅读