我有几个 struct :

struct FileView{
 name : String
 path : String
 //maybe other stuff
}
struct DirectoryView{
 files : Vec<FileView>
 //maybe other stuff
}

我想在DirectoryView的Iml中编写一个函数,该函数查找重复项(按名称),执行大约fs个操作来删除其中一个路径,并更新DirectoryView以删除那里的重复项.

这很棘手,因为要移出共享引用的限制,将可变引用放入相同数据的多个点(如窗口函数),以及重复数据删除函数不允许我对要清除的重复项执行额外操作的事实.到目前为止,我能做的最好的事情是:

fn purge_duplicates(&mut self) {
        self.files.sort_by(|a, b| a.name.cmp(&b.name));
        let mut prev_name = "rumplestilskin";
        let mut prev_path = "rumplestilskin";
        self.files.iter_mut().for_each(|file| {
            if file.name == prev_name {
                file.name = "DELETE_ME".to_owned();
                if file.path != prev_path {
                    std::fs::remove_file(&file.path).unwrap();
                }
            } else {
                prev_name = &file.name;
                prev_path = &file.path;
            }
        });
        self.files.retain(|file| file.name != "DELETE_ME");
    }

我不喜欢这样--神奇的"Lumplestilkin"和"Delete_ME"字符串,多次传球,都让我觉得乱七八糟.不过,我想出的其他 Select 至少也同样糟糕:

我可以为FileView派生Clone,使用窗口映射到一个全新的Vec<FileView>,并将self.files赋给它,但这感觉不太干净,只适用于可克隆的东西.

我可以标记要删除的文件的索引,然后以相反的顺序迭代这些索引.

我可能在心理上不明智,在文件视图被 destruct 时从磁盘上删除文件的方式实现了Drop.我看到的唯一缺点是,为了获得类似的结果,它比把硬盘放在微波炉里要稍微多做一些工作.

有什么好办法可以做到这点吗?

作为一个额外的问题-我想要一个更好的方法来确保我只删除磁盘上的文件,如果保留的文件具有不同的路径.(即,我不想仅仅因为引用了两次就删除唯一的实际文件.)

推荐答案

当您直接在保留中执行工作时,您不需要多次通过和"DELETE ME"个哨兵,此外,我们使用枚举,更具体地说是Option,而不是Rust中的"rumplestilskin"个哨兵.我不想使用FileView(坦率地说,使用String作为文件名和路径名是错误的),所以我改用PathBuf,在这里克隆它们是没有问题的,因为文件系统操作将使其运行时成本相形见绌:

use std::path::PathBuf;
fn purge_duplicates(files: &mut Vec<PathBuf>) {
    files.sort_unstable_by(|a, b| a.file_name().cmp(&b.file_name()));
    let mut previous = None::<PathBuf>;
    files.retain(|file| match previous {
        Some(ref prev)
            if file.file_name() == prev.file_name() && file.parent() != prev.parent() =>
        {
            if !file.is_symlink() && prev.is_symlink() {
                println!("remove_file({})", prev.display());
                previous = Some(file.clone());
            } else {
                println!("remove_file({})", file.display());
            }
            false
        }
        _ => {
            previous = Some(file.clone());
            true
        }
    });
}

fn main() {
    let mut files = vec![
        PathBuf::from("first/one"),
        PathBuf::from("first/one"),
        PathBuf::from("second/one"),
        PathBuf::from("first/two"),
        PathBuf::from("second/two"),
    ];

    purge_duplicates(&mut files);
    
    println!("remaining: {:?}", files);
}

打印:

remove_file(second/one)
remove_file(second/two)
remaining: ["first/one", "first/one", "first/two"]

Rust相关问答推荐

将此字符串转换为由空格字符分隔的空格

获取字符串切片(&;str)上的切片([ia..ib])返回字符串

无法理解铁 rust &S错误处理

MPSC频道在接收器处阻塞

如何点击()迭代器?

如何定义实现同名但返回类型不同的 struct 的函数

用于判断整数块是否连续的SIMD算法.

如何在不调用Collect()的情况下为新型vec实现IntoIterator?

如何创建一个可变的嵌套迭代器?

应为关联类型,找到类型参数

为什么特征默认没有调整大小?

结果流到 Vec 的结果:如何避免多个into_iter和collect?

面临意外的未对齐指针取消引用:地址必须是 0x8 的倍数,但为 0x__错误

Sized问题的动态调度迭代器Rust

为什么Rust编译器会忽略模板参数应具有静态生命周期?

是否可以通过可变引用推进可变切片?

不能将 `*self` borrow 为不可变的,因为它也被borrow 为可变的 - 编译器真的需要如此严格吗?

Rust 函数指针似乎被borrow 判断器视为有状态的

在空表达式语句中移动的值

在传输不可复制的值时实现就地枚举修改