【发布时间】:2021-01-05 00:42:07
【问题描述】:
我有一个struct Folder。我有一个名为contents 的方法。我希望该方法返回一个支持IntoIterator 的对象,以便调用者可以去
for x in folder.contents(){
...
}
Item 类型是(因为这是 hashmap 迭代器返回的 - 看低一点)
(&OsString, &FileOrFolder)
FileOrFolder 是一个枚举
enum FileOrFolder{
File(File),
Folder(Folder)
}
迭代器本身需要首先枚举文件夹拥有的HashMap<OSString, FileOrFolder>,然后再枚举Vec<File>。文件的Vec 是由内容fn 或IntoIterator 调用动态创建的,无论是否有效。我尝试简单地使用chain,但很快意识到这行不通。所以我对我正在尝试做的事情的粗略草图是这样的:
// the iterator
pub struct FFIter {
files: Vec<FileOrFolder>,
files_iter:Box<dyn Iterator<Item=FileOrFolder>>,
dirs: Box<dyn Iterator<Item = (&OsString, &FileOrFolder)>>,
dirs_done:bool
}
// the thing returned by the contents fn
struct FolderContents{
folder:&Folder
}
// make it iterable
impl IntoIterator for FolderContents {
type Item =(&OsString, &FileOrFolder);
type IntoIter = FFIter;
fn into_iter(self) -> Self::IntoIter {
let files = self.folder.make_the_files()
FFIter {
files: files, // to keep files 'alive'
files_iter: files.iter(),
dirs: Box::new(self.hashmap.iter()),
dirs_done:false
}
}
}
impl Iterator for FFIter {
type Item = (&OsString, &FileOrFolder);
fn next(&mut self) -> Option<(&OsString, &FileOrFolder)> {
None // return empty, lets just get the skeleton built
}
}
impl Folder{
pub fn contents(&self) -> FolderContents{
FolderContents{folder:&self}
}
}
我知道这充满了错误,但我需要知道这是否可行。如您所见,我什至没有尝试编写返回任何内容的代码。我只是想编译基本大纲。
我开始与终身系统搏斗,并达到了我拥有这个的地步
error[E0658]: generic associated types are unstable
--> src\state\files\file_or_folder.rs:46:5
|
46 | type Item<'a> =(&'a OsString, &'a FileOrFolder);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
这有点糟糕,因为编译器说我应该这样做。
我很高兴按照编译器/阅读/的建议继续努力解决这个问题……但过去我曾按照这些思路发布过一个问题,并被告知 - “当然不能这样做” .那么我应该能够完成这项工作吗?
文件夹类型不是Copy 并且克隆成本很高。文件类型为简单(string and i64)、Copy 和Clone
我知道我可以简单地让调用者调用两个不同的迭代并将它们合并,但我正在尝试编写一个透明的替换模块以放入现有的大型代码库中。
如果有人说chain() 应该很好用,我会再试一次。
EDIT Jmp 说链应该可以工作,
这是我尝试过的
pub fn contents(&self) -> Box<dyn Iterator<Item = (&OsString, &FileOrFolder)> + '_> {
let mut files = vec![];
if self.load_done {
for entry in WalkDir::new(&self.full_path)
.max_depth(1)
.skip_hidden(false)
.follow_links(false)
.into_iter()
{
let ent = entry.unwrap();
if ent.file_type().is_file() {
if let Some(name) = ent.path().file_name() {
files.push((
name.to_os_string(),
FileOrFolder::File(File {
name: name.to_os_string(),
size: ent.metadata().unwrap().len() as u128,
}),
));
}
}
}
};
Box::new(
self.contents
.iter()
.map(|(k, v)| (k, v))
.chain(files.iter().map(|x| (&x.0, &x.1))),
)
}
但是编译器正确地抱怨“文件”在调用结束时被破坏。我需要的是 vec 由迭代器持有,然后在迭代结束时删除。文件夹本身不能保存文件 - 这里的重点是动态填充文件,保存它们太昂贵了,内存明智。
【问题讨论】:
-
chain应该可以工作,但您需要确保两个迭代器具有相同的Item类型或使用map将一个(或两个)转换为适当的类型。跨度> -
@Jmb,这正是我试图做的(地图和链),但无法让它发挥作用。我会再试一次
-
@Jmb 不,我不知道该怎么做,文件的 vec 是动态创建的。我将更新 Q 以显示我喜欢的内容
-
“动态创建”和“在项目中带有引用的迭代器”通常根本不会一起出现。
-
@SebastianRedl - 我 100% 知道这一点。我正在征求意见该怎么做,我确信我可以将'on the fly' vec 存储在迭代器对象本身中。这就是我最初寻求帮助的原因,但 Jmp 说我应该只使用链
标签: rust