简体   繁体   中英

Rust closure return value

I'm a Rust beginner and am working on a small personal project. I'm working on a function that takes a Vec of records and turns them into strings to be used as rows in a CSV file.

My currently incomplete function looks like

pub fn write_csv_records<T: CSVWritable>( file_path: &str, seperator: char, records: Vec<Box<dyn CSVWritable>>, columns: Vec<String> ) -> ()
{
    let body = records.iter()
      .map(|r| r.to_csv_row() )
      .map(|row_values| {
           columns.iter()
           // this is my problem the closure in unwrap_or_else causes in issue!
             .map( |column| row_values.get( column ).unwrap_or_else(|| &String::from("") ).clone() )
             .collect::<Vec<String>>()
             .join( &seperator.to_string() )
      })
      .collect::<Vec<String>>()
      .join( "\n" );
}

I have had a persistent error that reads "cannot return a reference to data owned by the current function".

I'm at a loss for how to proceed. Is this related to lifetimes? Am I missing how unwrap_or_else works? What is the right way to provide a default value when something is absent in the row_values HashMap?

In your unwrap_or_else() call, you're returning the address of a function that's owned by the closure. This isn't allowed in Rust because that address is no longer valid after the closure finishes and that variable goes out of scope. Since you're just immediately cloning, you should instead return the actual String from the closure, not return the address of the String.

Also, if your CSVWritable trait returns something like a HashMap where the get() method returns a Option<&T> rather than Option<T> , then you need to do some extra work to get the underlying value (because you're collecting into Vector<String> and not Vector<&String> ). So you'll want something like this:

pub trait CSVWritable {
    fn to_csv_row(&self) -> std::collections::HashMap<String, String>;
}

pub fn write_csv_records(file_path: &str, seperator: char, records: Vec<Box<dyn CSVWritable>>, columns: Vec<String>) {
    let body = records
        .iter()
        .map(|r| r.to_csv_row())
        .map(|row_values| {
            columns
                .iter()
                .map(|column| match row_values.get(column) {
                    Some(s) => s.clone(),
                    None => String::from(""),
                })
                .collect::<Vec<String>>()
                .join(&seperator.to_string())
        })
        .collect::<Vec<String>>()
        .join("\n");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM