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或其他语言中那样工作。无论我尝
struct Dir
,其名称和向量为Box
'ed childstruct 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)
}
}