Rust中包装Filter迭代器无法编译问题求助
解决Rust中包装rusb设备迭代器的问题
核心问题分析
原代码的困境在于手动指定Filter的泛型参数过于繁琐且容易出错,我们可以通过两种方式简化:泛型结构体或动态分发迭代器,同时修正代码中的其他细节问题。
方案一:用泛型结构体隐藏复杂迭代器类型
这种方式保留静态分发的性能优势,同时避免手动书写冗长的泛型参数:
use rusb; const VENDOR: u16 = 0x046d; const PRODUCT: u16 = 0xc900; // 补充原代码缺失的常量定义 const LIBUSB_CLASS_HID: u8 = 3; struct LitraDevice { dev: rusb::Device<rusb::GlobalContext>, } pub struct LitraDevices { unfiltered: rusb::DeviceList<rusb::GlobalContext>, } // 用泛型参数替代具体的Filter类型,简化结构体定义 struct LitraDeviceIterator<I> where I: Iterator<Item = rusb::Device<rusb::GlobalContext>>, { inner: I, } impl LitraDevices { pub fn new() -> Self { let unfiltered = rusb::devices().unwrap(); LitraDevices { unfiltered } } // 调整逻辑:返回true表示保留该设备,避免反向判断的混淆 fn should_keep(dev: &rusb::Device<rusb::GlobalContext>) -> bool { let desc = match dev.device_descriptor() { Ok(d) => d, Err(_) => return false, // 忽略获取描述符失败的设备,避免panic }; (desc.vendor_id(), desc.product_id()) == (VENDOR, PRODUCT) && desc.class_code() != LIBUSB_CLASS_HID } // 直接返回impl Iterator,无需手动包装结构体(若不需要额外迭代器逻辑) pub fn iter(self) -> impl Iterator<Item = LitraDevice> { self.unfiltered .iter() .filter(Self::should_keep) .map(|dev| LitraDevice { dev }) } } // 若需要自定义迭代器的额外行为,实现Iterator trait impl<I> Iterator for LitraDeviceIterator<I> where I: Iterator<Item = rusb::Device<rusb::GlobalContext>>, { type Item = LitraDevice; fn next(&mut self) -> Option<Self::Item> { self.inner.next().map(|dev| LitraDevice { dev }) } }
方案二:用动态分发简化结构体
如果不需要静态分发的极致性能,Box<dyn Iterator>可以彻底避免泛型参数的困扰:
use rusb; const VENDOR: u16 = 0x046d; const PRODUCT: u16 = 0xc900; const LIBUSB_CLASS_HID: u8 = 3; struct LitraDevice { dev: rusb::Device<rusb::GlobalContext>, } pub struct LitraDevices { unfiltered: rusb::DeviceList<rusb::GlobalContext>, } struct LitraDeviceIterator<'a> { inner: Box<dyn Iterator<Item = LitraDevice> + 'a>, } impl LitraDevices { pub fn new() -> Self { let unfiltered = rusb::devices().unwrap(); LitraDevices { unfiltered } } fn should_keep(dev: &rusb::Device<rusb::GlobalContext>) -> bool { let desc = match dev.device_descriptor() { Ok(d) => d, Err(_) => return false, }; (desc.vendor_id(), desc.product_id()) == (VENDOR, PRODUCT) && desc.class_code() != LIBUSB_CLASS_HID } pub fn iter<'a>(self) -> LitraDeviceIterator<'a> { let iter = self.unfiltered .iter() .filter(Self::should_keep) .map(|dev| LitraDevice { dev }); LitraDeviceIterator { inner: Box::new(iter), } } } impl<'a> Iterator for LitraDeviceIterator<'a> { type Item = LitraDevice; fn next(&mut self) -> Option<Self::Item> { self.inner.next() } }
关键修正点
- 逻辑可读性优化:将原反向判断的
can_not_handle重命名为should_keep,避免逻辑混淆。 - 错误处理:替换
unwrap()为match,忽略获取设备描述符失败的设备,避免程序panic。 - 常量补充:添加原代码缺失的
LIBUSB_CLASS_HID常量定义。 - 迭代器简化:若无需自定义迭代器的额外行为,直接返回
impl Iterator可以完全省去手动定义LitraDeviceIterator的步骤。
内容的提问来源于stack exchange,提问作者abergmeier
相关产品推荐
相关产品推荐

