如何在结构体字段中构造显式Iterator类型?
Rust返回含Iterator的结构体时类型不匹配错误
尝试将Iterator作为结构体字段dirs返回,编写了如下代码:
use std::{ fs::{self, DirEntry}, io::Error, path::{Path, PathBuf}, }; struct Leds<I: Iterator<Item = PathBuf>> { dirs: I, } pub fn find_leds<P, I>(path: P) -> Leds<I> where I: Iterator<Item = PathBuf>, P: AsRef<Path>, { let paths = fs::read_dir(path).unwrap(); let map = |dir_res: Result<DirEntry, Error>| -> Option<PathBuf> { if dir_res.is_err() { return None; } let p = dir_res.unwrap(); let file_type = p.file_type(); if file_type.is_err() { return None; } if !file_type.unwrap().is_dir() { return None; } return Some(p.path()); }; Leds { dirs: paths.filter_map(map), } }
运行后出现如下错误:
error[E0308]: mismatched types --> src/dirs.rs:33:15 | 11 | pub fn find_leds<P, I>(path: P) -> Leds<I> | - this type parameter ... 17 | let map = |dir_res: Result<DirEntry, Error>| -> Option<PathBuf> { | ----------------------------------------------------- the found closure ... 33 | dirs: paths.filter_map(map), | ^^^^^^^^^^^^^^^^^^^^^ expected type parameter `I`, found struct `std::iter::FilterMap` | = note: expected type parameter `I` found struct `std::iter::FilterMap<ReadDir, [closure@src/dirs.rs:17:15: 17:68]>`
错误原因
你在find_leds函数中声明了类型参数I,这意味着调用方有权指定I的具体类型,但函数内部实际生成的是FilterMap<ReadDir, 闭包>这个固定的具体迭代器类型——两者类型不匹配,因为调用方指定的I和函数返回的具体类型无法对齐。
解决方法
方案1:使用impl Trait返回具体类型(推荐)
如果你的Rust版本≥1.51,可以在结构体中直接使用impl Trait作为字段类型;若版本更低,可以让函数返回包裹了impl Iterator的结构体,或者直接返回迭代器本身。修改后的代码如下:
use std::{ fs::{self, DirEntry}, io::Error, path::{Path, PathBuf}, }; // 结构体字段使用impl Trait存储迭代器 struct Leds { dirs: impl Iterator<Item = PathBuf>, } pub fn find_leds<P>(path: P) -> Leds where P: AsRef<Path>, { let paths = fs::read_dir(path).unwrap(); // 用?简化错误处理 let map = |dir_res: Result<DirEntry, Error>| -> Option<PathBuf> { let entry = dir_res.ok()?; let file_type = entry.file_type().ok()?; file_type.is_dir().then(|| entry.path()) }; Leds { dirs: paths.filter_map(map), } }
方案2:使用 trait object(动态分发)
如果需要对结构体做更灵活的类型抽象,可以用Box<dyn Iterator>作为字段类型,通过动态分发实现类型擦除:
use std::{ fs::{self, DirEntry}, io::Error, path::{Path, PathBuf}, }; struct Leds { dirs: Box<dyn Iterator<Item = PathBuf>>, } pub fn find_leds<P>(path: P) -> Leds where P: AsRef<Path>, { let paths = fs::read_dir(path).unwrap(); let map = |dir_res: Result<DirEntry, Error>| -> Option<PathBuf> { let entry = dir_res.ok()?; let file_type = entry.file_type().ok()?; file_type.is_dir().then(|| entry.path()) }; Leds { dirs: Box::new(paths.filter_map(map)), } }
内容的提问来源于stack exchange,提问作者abergmeier
相关产品推荐
相关产品推荐

