Search code examples
functioncsvrustreturn-type

rust return type issue in simple function


I'm having a misunderstanding about return types in rust. coming from JavaScript and thinking I understood the core concepts of mutating, scopes, etc. But now I'm stuck at a simple return type.

fn main() {
  let input = "./assets/input.csv";
  let list = get_csv(&input);

  for result in list.records() {
    let record = result?;
    println!("{:?}", record);
  }
}


fn get_csv(csv_path: &str) -> csv::Reader {
  return csv::Reader::from_path(csv_path);
}

I will get the error

mismatched types

expected struct `csv::Reader`, found enum `std::result::Result`

note: expected struct `csv::Reader<&str>`
           found enum `std::result::Result<csv::Reader<std::fs::File>, csv::Error>`
note: to return `impl Trait`, all returned values must be of the same type
note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
help: you could instead create a new `enum` with a variant for each returned typerustc(E0308)

UPDATE:

fn get_csv (filepath: &str) -> csv::Result<csv::Reader<File>>{
    let mut reader =  csv::ReaderBuilder::new();
    let mut list = match reader
    .delimiter(b';')
    .from_path(&filepath) {
        Ok(list) => list,
        Err(error) => {
            println!("Failed to open file. {}", error);
            return;
        }
    };
    return list;
}

Solution

  • The error message is telling you that what the method returns (Result) is different from what you have defined (csv::Reader). When you check the documentation for the from_path method, you see that it is defined as:

    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Reader<File>>
    

    The return value of the function is a Result enum that has two states: Ok or Err. If for example the given file doesn't exist, you cannot create a reader for it. In your code, you have to handle the case that the reader cannot be created. For example:

    use csv::Reader;
    
    fn main() {
        let input = "./assets/input.csv";
    
        let mut list = match Reader::from_path(&input) {
            Ok(list) => list,
            Err(error) => {
                println!("Failed to open file. {}", error);
                return;
            }
        };
    
        for result in list.records() {
            let record = result.unwrap();
            println!("{:?}", record);
        }
    }
    

    The Rust book has more information on the Result enum: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html

    The Reader that gets returned in the Result is a generic type, which means that it provides a generic implementation that can be used with different concrete Rust types. Reader<File> is the notation that tells the Rust compiler that this instance of Reader is used to read from a File. But technically, Reader supports anything that implements the std::io::Read trait (see the source). For example, you could use to read CSV files from a network stream, or have the user type them into STDIN and read them from the terminal line-by-line.