Recursion 如何在Rust中将目录路径的平面列表转换为层次结构?

Recursion 如何在Rust中将目录路径的平面列表转换为层次结构?,recursion,rust,tree,hierarchy,hierarchical,Recursion,Rust,Tree,Hierarchy,Hierarchical,我的输入是一个文件系统路径的平面列表,这些路径是单个顶级目录的所有子目录(或其中的文件) 我的最终输出应该是: 路径的文本层次显示,如unix树命令 逻辑结构与(1)匹配的路径的分层JSON序列化 我创建了一个中间数据结构,它是一个自引用的struct Dir,其名称和向量为Box'ed childstruct Dir 我可以成功地使用Dir表示任意目录树,如下面的输出所示 我想用一个堆栈来处理列表,为每个子目录添加一个Dir,并在升序时弹出,但我似乎无法让它像在C或其他语言中那样工作。无论我尝

我的输入是一个文件系统路径的平面列表,这些路径是单个顶级目录的所有子目录(或其中的文件)

我的最终输出应该是:

  • 路径的文本层次显示,如unix命令
  • 逻辑结构与(1)匹配的路径的分层JSON序列化
  • 我创建了一个中间数据结构,它是一个自引用的
    struct Dir
    ,其名称和向量为
    Box
    'ed child
    struct Dir

    我可以成功地使用
    Dir
    表示任意目录树,如下面的输出所示

    我想用一个堆栈来处理列表,为每个子目录添加一个
    Dir
    ,并在升序时弹出,但我似乎无法让它像在C或其他语言中那样工作。无论我尝试什么,我都会遇到编译器错误

    如何将平面列表转换为
    Dir
    并使编译器满意?或者,如何以不同的方式实现(1)和(2)

    代码:


    由于有人删除了我以前的答案,并带有一个指向工作代码的链接,我将在这里发布完整的工作代码

    // A type to represent a path, split into its component parts
    #[derive(Debug)]
    struct Path {
        parts: Vec<String>,
    }
    impl Path {
        pub fn new(path: &str) -> Path {
            Path {
                parts: path.to_string().split("/").map(|s| s.to_string()).collect(),
            }
        }
    }
    
    // A recursive type to represent a directory tree.
    // Simplification: If it has children, it is considered
    // a directory, else considered a file.
    #[derive(Debug, Clone)]
    struct Dir {
        name: String,
        children: Vec<Box<Dir>>,
    }
    
    impl Dir {
        fn new(name: &str) -> Dir {
            Dir {
                name: name.to_string(),
                children: Vec::<Box<Dir>>::new(),
            }
        }
    
        fn find_child(&mut self, name: &str) -> Option<&mut Dir> {
            for c in self.children.iter_mut() {
                if c.name == name {
                    return Some(c);
                }
            }
            None
        }
    
        fn add_child<T>(&mut self, leaf: T) -> &mut Self
        where
            T: Into<Dir>,
        {
            self.children.push(Box::new(leaf.into()));
            self
        }
    }
    
    fn dir(val: &str) -> Dir {
        Dir::new(val)
    }
    
    fn main() {
        // Form our INPUT:  a list of paths.
        let paths = vec![
            Path::new("child1/grandchild1.txt"),
            Path::new("child1/grandchild2.json"),
            Path::new("child2/grandchild3.pdf"),
            Path::new("child3"),
        ];
        println!("Input Paths:\n{:#?}\n", paths);
    
        // Transformation:
        // A recursive algorithm that converts the list of paths
        // above to Dir (tree) below.
        // ie: paths --> dir
        let mut top = dir("root");
        for path in paths.iter() {
            build_tree(&mut top, &path.parts, 0);
        }
    
        println!(
            "Intermediate Representation of Dirs:\n{:#?}\n\nOutput Tree Format:\n",
            top
        );
    
        // Output:  textual `tree` format
        print_dir(&top, 0);
    }
    
    fn build_tree(node: &mut Dir, parts: &Vec<String>, depth: usize) {
        if depth < parts.len() {
            let item = &parts[depth];
    
            let mut dir = match node.find_child(&item) {
                Some(d) => d,
                None => {
                    let d = Dir::new(&item);
                    node.add_child(d);
                    match node.find_child(&item) {
                        Some(d2) => d2,
                        None => panic!("Got here!"),
                    }
                }
            };
            build_tree(&mut dir, parts, depth + 1);
        }
    }
    
    // A function to print a Dir in format similar to unix `tree` command.
    fn print_dir(dir: &Dir, depth: u32) {
        if depth == 0 {
            println!("{}", dir.name);
        } else {
            println!(
                "{:indent$}{} {}",
                "",
                "└──",
                dir.name,
                indent = ((depth as usize) - 1) * 4
            );
        }
    
        for child in dir.children.iter() {
            print_dir(child, depth + 1)
        }
    }
    
    //表示路径的类型,拆分为其组成部分
    #[导出(调试)]
    结构路径{
    部分:Vec,,
    }
    impl路径{
    pub fn new(路径:&str)->path{
    路径{
    部分:path.to_string().split(“/”).map(|s|s.to_string()).collect(),
    }
    }
    }
    //表示目录树的递归类型。
    //简化:如果它有子对象,则会被考虑
    //目录,否则视为文件。
    #[派生(调试、克隆)]
    结构目录{
    名称:String,
    儿童:Vec,
    }
    impl目录{
    fn新(名称:&str)->Dir{
    迪尔{
    name:name.to_string(),
    子项:Vec:::new(),
    }
    }
    fn查找子项(&mut self,name:&str)->选项{
    对于self.children.iter_mut()中的c{
    如果c.name==name{
    返回一些(c);
    }
    }
    没有一个
    }
    fn添加子项(&mut-self,叶:T)->&mut-self
    哪里
    T:Into,
    {
    self.children.push(Box::new(leaf.into());
    自己
    }
    }
    fn目录(val:&str)->dir{
    目录::新(val)
    }
    fn main(){
    //形成我们的输入:路径列表。
    让路径=向量[
    Path::new(“child1/grand1.txt”),
    Path::new(“child1/grand2.json”),
    Path::new(“child2/grand3.pdf”),
    路径::新建(“child3”),
    ];
    println!(“输入路径:\n{:?}\n”,路径);
    //转变:
    //转换路径列表的递归算法
    //从上面到下面的目录(树)。
    //ie:路径-->目录
    让mut top=dir(“根”);
    对于paths.iter()中的路径{
    构建树(&mut-top,&path.parts,0);
    }
    普林顿(
    “目录的中间表示:\n{:#?}\n\n输出树格式:\n”,
    顶部
    );
    //输出:文本“树”格式
    打印目录(&top,0);
    }
    fn构建树(节点:&mut Dir,部分:&Vec,深度:usize){
    如果深度d,
    无=>{
    设d=Dir::new(&item);
    节点。添加子节点(d);
    匹配节点。查找子节点(&item){
    一些(d2)=>d2,
    无=>恐慌!(“到了!”),
    }
    }
    };
    构建_树(&mut dir,parts,depth+1);
    }
    }
    //以类似于unix“tree”命令的格式打印目录的函数。
    fn打印目录(目录:&dir,深度:u32){
    如果深度==0{
    println!(“{}”,目录名);
    }否则{
    普林顿(
    “{:缩进$}{}{}”,
    "",
    "└──",
    董事姓名,
    缩进=((使用时的深度)-1)*4
    );
    }
    对于dir.children.iter()中的child{
    打印方向(子级,深度+1)
    }
    }
    
    您的问题似乎可以用的答案来回答。如果不是,请您的问题解释差异。否则,我们可以将此问题标记为已回答。值得指出的是,字符串不是表示路径的好方法。这就是Rust具有类型和friends的原因。thx但表示路径不是在我询问的时候。将路径列表转换为层次结构是目标。我阅读了您提供的链接,但它没有解决问题。我已经使用&self尝试了各种方法,但都没有用——使用clone()我认为这是毫无意义的。因此,如果你把这个问题标记为已回答,我将不会比我问它时更接近于一个解决方案。我在谷歌搜索了所有地方,我没有发现任何人做我试图做的事情的例子,这在rust中一定是可能的,但对像我这样学习语言的人来说并不明显。如果这个链接是相关的,也许您可以很好地修改我提供的代码,并演示它是如何准确地解决它的。另请参见。
    // A type to represent a path, split into its component parts
    #[derive(Debug)]
    struct Path {
        parts: Vec<String>,
    }
    impl Path {
        pub fn new(path: &str) -> Path {
            Path {
                parts: path.to_string().split("/").map(|s| s.to_string()).collect(),
            }
        }
    }
    
    // A recursive type to represent a directory tree.
    // Simplification: If it has children, it is considered
    // a directory, else considered a file.
    #[derive(Debug, Clone)]
    struct Dir {
        name: String,
        children: Vec<Box<Dir>>,
    }
    
    impl Dir {
        fn new(name: &str) -> Dir {
            Dir {
                name: name.to_string(),
                children: Vec::<Box<Dir>>::new(),
            }
        }
    
        fn find_child(&mut self, name: &str) -> Option<&mut Dir> {
            for c in self.children.iter_mut() {
                if c.name == name {
                    return Some(c);
                }
            }
            None
        }
    
        fn add_child<T>(&mut self, leaf: T) -> &mut Self
        where
            T: Into<Dir>,
        {
            self.children.push(Box::new(leaf.into()));
            self
        }
    }
    
    fn dir(val: &str) -> Dir {
        Dir::new(val)
    }
    
    fn main() {
        // Form our INPUT:  a list of paths.
        let paths = vec![
            Path::new("child1/grandchild1.txt"),
            Path::new("child1/grandchild2.json"),
            Path::new("child2/grandchild3.pdf"),
            Path::new("child3"),
        ];
        println!("Input Paths:\n{:#?}\n", paths);
    
        // Transformation:
        // A recursive algorithm that converts the list of paths
        // above to Dir (tree) below.
        // ie: paths --> dir
        let mut top = dir("root");
        for path in paths.iter() {
            build_tree(&mut top, &path.parts, 0);
        }
    
        println!(
            "Intermediate Representation of Dirs:\n{:#?}\n\nOutput Tree Format:\n",
            top
        );
    
        // Output:  textual `tree` format
        print_dir(&top, 0);
    }
    
    fn build_tree(node: &mut Dir, parts: &Vec<String>, depth: usize) {
        if depth < parts.len() {
            let item = &parts[depth];
    
            let mut dir = match node.find_child(&item) {
                Some(d) => d,
                None => {
                    let d = Dir::new(&item);
                    node.add_child(d);
                    match node.find_child(&item) {
                        Some(d2) => d2,
                        None => panic!("Got here!"),
                    }
                }
            };
            build_tree(&mut dir, parts, depth + 1);
        }
    }
    
    // A function to print a Dir in format similar to unix `tree` command.
    fn print_dir(dir: &Dir, depth: u32) {
        if depth == 0 {
            println!("{}", dir.name);
        } else {
            println!(
                "{:indent$}{} {}",
                "",
                "└──",
                dir.name,
                indent = ((depth as usize) - 1) * 4
            );
        }
    
        for child in dir.children.iter() {
            print_dir(child, depth + 1)
        }
    }