Creating Vector of files in directory (without path/extension)

Greetings! This happens to be my first post here.

I am trying to get the list of files in a directory. User will create multiple .html files there. I want to extract their names in a Vec<&str> (as each file denotes a different category). I want to store the names (without extension or parent path) in a vector to use later on.

This is the function I'm using to get list of files : (I believe this is correct, but posting, just in case)

fn available_categories() ->  io::Result<Vec<PathBuf>>{

    let mut categories = vec![];

    for path in fs::read_dir("./categories/")? {
        let path = path?.path();
        if let Some("html") = path.extension().and_then(OsStr::to_str) {
            categories.push(path.to_owned());
        }
    }
    Ok(categories)
}

This returns a vector of PathBuf.

Following code prints the available files (or what I'm calling categories, as each file defines a category), using the function above.

let categories = available_categories().unwrap();
  
for category in categories{
    let category_name = category.display().to_string();
    println!("{}", &category_name[11..(category_name.len()-5)]); 
    // String slicing to prevent printing path and extension
    // We only care about the file name which is also category name
}

The output is

c
a
b
d

(Not alphabetical for some reason, but its not an issue for what I intend to do)

Now, I want to store this output in a Vec<&str>.

I tried following code

let categories = available_layouts().unwrap();
  
let mut category_list : Vec<&str> = vec![];
let mut path: String;

for category in categories{
    path = category.display().to_string();
    category_list.push(&path[11..(path.len()-5)]);
}

// We use categories_list later in here

Error log

   |
15 |         path = category.display().to_string();
   |         ^^^^ assignment to borrowed `path` occurs here
16 |         category_list.push(&path[11..(path.len()-5)]);
   |         -------------       ---- borrow of `path` occurs here
   |         |
   |         borrow later used here

I seem to understand why this code is wrong. But I cannot come up with the correct solution to this.

Any help or pointers appreciated.

Thank You!

For that, you must have the corresponding data somewhere - either as String or as fixed data (i.e. &static str). In most cases, you want to use Vec<String>, not Vec<&str>.

1 Like

tl;dr : String::from didn't work to convert a string slice into String, but .to_string() method worked. Could I request you to briefly explain why this happened?


I indeed tried using String first, but the issue was in this statement:

category_list.push(String::from(path[11..(path.len()-5)]));

This gave 2 errors

  • String::from(...
    the trait From<str> is not implemented for String
  • path[11..(path.len()-5)]
    doesn't have a size known at compile-time

Playing around after I made the original post, I tried .to_string() method and it (magically) worked!

For any future visitor to this post, the line below worked:

category_list.push((path[11..(path.len()-5)]).to_string());

I still need to understand why String::from did not work and why .to_string() worked.

You usually need to put a str behind a reference to work with it (&str):

-category_list.push(String::from(path[11..(path.len()-5)]));
+category_list.push(String::from(&path[11..(path.len()-5)]));
+//                              ^

Rust tries hard to find an applicable method, including adding up to one level of & (which doesn't happen as a normal parameter).

1 Like

That explained well. Thank you!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.