This function only returns a empty array

I wrote a function that parses text from a .txt file,and I'm unsure why it's not printing anything when the function is run. I have included the complete code,along with the main function below. Thanks for your time.

use std::fs::File;
use std::io::{BufRead, BufReader};
use std::env;
fn main() {
    let filename = "wordlist.txt";
    let content_lists = read_file_to_lists(filename, 1);

    for sublist in content_lists {
        for word in sublist {
            println!("{}", word);
        }
        println!("---");
    }
}



fn read_file_to_lists(filename: &str, param: u32) -> Vec<Vec<String>> {
    let mut lists: Vec<Vec<String>> = Vec::new();
    let sublist_len: usize;

    match param {
        0 => sublist_len = 4,
        1 => sublist_len = 6,
        2 => sublist_len = 9,
        _ => {
            println!("Invalid parameter value. Defaulting to sublist length 4.");
            sublist_len = 4;
        }
    }

    if let Ok(mut exe_path) = env::current_exe() {
        exe_path.pop(); // Remove executable file name
        let filepath = exe_path.join(filename);

        if let Ok(file) = File::open(filepath) {
            let reader = BufReader::new(file);

            let mut sublist: Vec<String> = Vec::new();

            for line in reader.lines() {
                if let Ok(word) = line {
                    let word_list: Vec<String> = word.split_whitespace().map(|s| s.to_string()).collect();
                    sublist.push(word);

                    for word in word_list {
                        sublist.push(word);
                        if sublist.len() == sublist_len {
                            lists.push(sublist);
                            sublist = Vec::new();
                        }
                    }
                }
            }

            if !sublist.is_empty() {
                lists.push(sublist);
            }
        }
    }

    lists
}

You have multiple if let that don't have an else branch. For the two outer ones, if one of those fails then the list will be empty.

Also, I don't think that reader.lines() iterator returns a Result. So this if let would also never execute.

Edit

Nevermind, it does return an io::Result

Thanks for pointing that out, tunnelvisioned on what could be causing the error since this code was functional previously and forgot to add else conditions. The error is happening on the second if condition, since it's having a issue with the filepath. The file however is in the same directory as the file that contains the code,so I'm not sure what error could be occurring with the filepath?

1 Like

Be default paths are resolved at runtime relative to a "current directory" set by the calling program, not a source file location. In this case, assuming you're using cargo run, that will be in the root of your package, next to Cargo.toml.

If you want to include the file content when you build, so it will be relative to the source, use include_str!("some literal path").

You probably want to start looking into returning Results so you're not confused by things failing. Give the anyhow and thiserror crates a look for two complimentary solutions.

Thanks for the suggested crates,will look into them. Would this be how you incorporate include_str! into the function?

fn read_file_to_lists(filename: &str, param: u32) -> Vec<Vec<String>> {
    let mut lists: Vec<Vec<String>> = Vec::new();
    let sublist_len: usize;

    match param {
        0 => sublist_len = 4,
        1 => sublist_len = 6,
        2 => sublist_len = 9,
        _ => {
            println!("Invalid parameter value. Defaulting to sublist length 4.");
            sublist_len = 4;
        }
    }

    let content = include_str!(filename);
    let reader = BufReader::new(content.as_bytes());

    let mut sublist: Vec<String> = Vec::new();

    for line in reader.lines() {
        if let Ok(word) = line {
            let word_list: Vec<String> = word.split_whitespace().map(|s| s.to_string()).collect();
            sublist.push(word);

            for word in word_list {
                sublist.push(word);
                if sublist.len() == sublist_len {
                    lists.push(sublist);
                    sublist = Vec::new();
                }
            }
        }
    }

    if !sublist.is_empty() {
        lists.push(sublist);
    }

    lists
}

No, this does not work. include_str! is a macro that expands to the content of a file at compile-time, which means that you can't call it with a runtime value like filename. Instead, you could e.g. call include_str!("my_file.txt") in your main function and take the contents of the file as an &str argument.

1 Like

Also, if you're immediately going to take as_bytes(), you can simply use include_bytes!() to get [u8], though then you're not guaranteed to have the content be UTF-8.

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.