我的输入是一个文件系统路径的扁平列表,它们都是单个顶层目录下的子目录(或其中的文件)。
我的最终输出应该是:
1. 文本层次结构显示路径,类似于UNIX tree命令。 2. 路径的分层JSON序列化,与(1)具有匹配的逻辑结构。
我创建了一种中间数据结构,这是一个自引用的 Dir 结构体,它具有名称和 Box 包装的子目录 Dir 的向量。
我可以成功地使用 Dir 表示任意目录树,如下面的输出所示。
我想使用堆栈处理列表,在每个子目录中添加一个 Dir 并在上升时弹出,但是我似乎无法像在 C 或其他语言中那样让Rust编译器成功。无论我尝试什么,都会得到编译器错误。
如何将扁平列表转换为 Dir 并使编译器满意?或者以其他方式实现(1)和(2)?
我的最终输出应该是:
1. 文本层次结构显示路径,类似于UNIX tree命令。 2. 路径的分层JSON序列化,与(1)具有匹配的逻辑结构。
我创建了一种中间数据结构,这是一个自引用的 Dir 结构体,它具有名称和 Box 包装的子目录 Dir 的向量。
我可以成功地使用 Dir 表示任意目录树,如下面的输出所示。
我想使用堆栈处理列表,在每个子目录中添加一个 Dir 并在上升时弹出,但是我似乎无法像在 C 或其他语言中那样让Rust编译器成功。无论我尝试什么,都会得到编译器错误。
如何将扁平列表转换为 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)]
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 has_child(&self, name: &str) -> bool {
for c in self.children.iter() {
if c.name == name {
return true;
}
}
false
}
fn add_child<T>(mut self, leaf: T) -> 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("root/child1/grandchild1.txt"),
Path::new("root/child1/grandchild2.json"),
Path::new("root/child2/grandchild3.pdf"),
Path::new("root/child3"),
];
println!("Input Paths:\n{:#?}\n", paths);
// Transformation:
// I need an algorithm here that converts the list of paths
// above to a recursive struct (tree) below.
// ie: paths --> dir
let top = dir("root");
let mut cwd = ⊤
for p in paths.iter() {
for part in p.parts.iter() {
if !cwd.has_child(part) {
// cwd.add_child(dir(part));
// cwd = &cwd.children[cwd.children.len() - 1];
}
}
}
// Intermediate Representation:
// The above transformation should result in the following
// hierarchical structure.
let top = dir("root")
.add_child(
dir("child1")
.add_child(dir("grandchild1.txt"))
.add_child(dir("grandchild2.json")),
)
.add_child(dir("child2").add_child(dir("grandchild3.pdf")))
.add_child(dir("child3"));
println!("Intermediate Representation of Dirs:\n{:#?}\n\nOutput Tree Format:\n", top);
// Output: textual `tree` format
print_dir(&top, 0);
}
// 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)
}
}
输出:
$ ./target/debug/rust-tree
Input Paths:
[
Path {
parts: [
"root",
"child1",
"grandchild1.txt",
],
},
Path {
parts: [
"root",
"child1",
"grandchild2.json",
],
},
Path {
parts: [
"root",
"child2",
"grandchild3.pdf",
],
},
Path {
parts: [
"root",
"child3",
],
},
]
Intermediate Representation of Dirs:
Dir {
name: "root",
children: [
Dir {
name: "child1",
children: [
Dir {
name: "grandchild1.txt",
children: [],
},
Dir {
name: "grandchild2.json",
children: [],
},
],
},
Dir {
name: "child2",
children: [
Dir {
name: "grandchild3.pdf",
children: [],
},
],
},
Dir {
name: "child3",
children: [],
},
],
}
Output Tree Format:
root
└── child1
└── grandchild1.txt
└── grandchild2.json
└── child2
└── grandchild3.pdf
└── child3
Path
类型和相关工具的原因。 - Shepmaster