Search code examples
rustpattern-matchingdeserialization

Mismatched types error while deserializing with pattern matching


I'm attempting to deserialize a csv value into a different type of struct based on a value passed into a function.

I am not understanding why I am receiving a mismatched types error. Why does it find struct CitiRec when it lives in a different match arm?

pub fn get_uncat_rec(path: &PathBuf, bank_type: BankType) -> Vec<UnCatRecord> {
  let mut reader = csv::Reader::from_path(path).unwrap();
  let mut uncat_rec: Vec<UnCatRecord> = Vec::new();

  for record in reader.deserialize() {
    match bank_type {
      BankType::Citi => {
        let rec_result: Result<CitiRec, csv::Error> = record;
        match rec_result {
          Ok(rec_result) => {
            uncat_rec.push(rec_result.to_uncat_rec());
          }
          Err(err) => {
            println!("Error received deserializing Citi Record: {}", err);
          }
        }
      }
      BankType::Kasaka => {
        let rec_result: Result<KasakaRec, csv::Error> = record; <-- **error here**
        match rec_result {
          Ok(rec_result) => {
            uncat_rec.push(rec_result.to_uncat_rec());
          }
          Err(err) => {
            println!("Error received deserializing Kasaka Record: {}", err);
          }
        }
      }
      _ => {}
    }

Here is the error that receive:

error[E0308]: mismatched types                                                                                                                                                                                                                       
  --> src\normalizer.rs:26:57
   |
26 |         let rec_result: Result<KasakaRec, csv::Error> = record;
   |                         -----------------------------   ^^^^^^ expected struct `KasakaRec`, found struct `CitiRec`
   |                         |
   |                         expected due to this
   |
   = note: expected enum `Result<KasakaRec, _>`
              found enum `Result<CitiRec, _>`

Solution

  • The type cannot be conditional. record has one, and exactly one, type.

    From the first match arm the compiler is concluding that you're deserializing into CitiRecs. But in the second it appears that you are deserializing into KasakaRecs, and this is a conflict.

    A way to solve that is to have a separate loop for each arm, so we can deserialize to different types:

    pub fn get_uncat_rec(path: &PathBuf, bank_type: BankType) -> Vec<UnCatRecord> {
        let mut reader = csv::Reader::from_path(path).unwrap();
        let mut uncat_rec: Vec<UnCatRecord> = Vec::new();
    
        match bank_type {
            BankType::Citi => {
                for record in reader.deserialize() {
                    let rec_result: Result<CitiRec, csv::Error> = record;
                    match rec_result {
                        Ok(rec_result) => {
                            uncat_rec.push(rec_result.to_uncat_rec());
                        }
                        Err(err) => {
                            println!("Error received deserializing Citi Record: {}", err);
                        }
                    }
                }
            }
            BankType::Kasaka => {
                for record in reader.deserialize() {
                    let rec_result: Result<KasakaRec, csv::Error> = record;
                    match rec_result {
                        Ok(rec_result) => {
                            uncat_rec.push(rec_result.to_uncat_rec());
                        }
                        Err(err) => {
                            println!("Error received deserializing Kasaka Record: {}", err);
                        }
                    }
                }
            }
            _ => {}
        }
    }