匹配多种可能的类型?

aco*_*tad 4 match rust xlsxwriter pyo3

我对 Rust 非常非常陌生,并且由于我强大的弱类型编程背景,我一直在努力解决它。

下面的代码应将通过 PYO3 从 Python 接收的数据写入 XLSX 工作表中。我只是不知道如何处理最后一个匹配,因为“value”是 PyAny 类型(也就是说,它的方法 extract 可以输出多种类型,例如 String、f32 等,并且我想要根据提取的特定行为类型)。

也许我可以为每个潜在的提取类型链接匹配(如果第一个输出 Err,请尝试下一个),但我怀疑可能有更好的方法。也许我只是用错误的设计来解决这个问题。任何见解都将受到欢迎。

pub trait WriteValue {
    fn write_value(&self, worksheet: &mut Worksheet, row: u32, col: u16, format: Option<&Format>) -> Result<(), XlsxError>;
}

impl WriteValue for String {
    fn write_value(&self, worksheet: &mut Worksheet, row: u32, col: u16, format: Option<&Format>) -> Result<(), XlsxError> {
        worksheet.write_string(row, col, &self, format)
    }
}

impl WriteValue for f32 {
    fn write_value(&self, worksheet: &mut Worksheet, row: u32, col: u16, format: Option<&Format>) -> Result<(), XlsxError> {
        worksheet.write_number(row, col, f64::from(*self), format)
    }
}

fn _write(path: &str, data: HashMap<u32, &PyList>, _highlight: Option<&PyDict>) -> Result<(), XlsxError> {
    let workbook = Workbook::new(path);
    let mut worksheet = workbook.add_worksheet(None)?;

    let format_bold = workbook.add_format().set_bold();

    for (row_index, values) in data {

        let mut col_idx: u16 = 0;

        for value in values {
            col_idx += 1;
            let row_format= match &row_index {
                0 => Some(&format_bold),
                _ => None
                };
            match value.extract::<String>() {
                Ok(x) => x.write_value(&mut worksheet, row_index.clone(), &col_idx -1, row_format)?,
                Err(_) => { }
                }
        }
    }
    workbook.close()
    }
Run Code Online (Sandbox Code Playgroud)

Mas*_*inn 6

这主要是 pyo3 API 问题,我认为 pyo3 没有内置的“multiextract”,尽管我对它不是很熟悉,所以可能是这样。

然而,首先,由于您不关心子句,因此Err您可以通过简单地链接if let语句来简化代码,它们是语法糖,但对于一元或二元布尔条件,它们确实很方便,例如

if let Ok(x) = value.extract::<String>() {
    x.write_value(...)
} else if let Ok(x) = value.extract::<f32>() {
    // handle this case and possibly add a bunch more
} else {
    // handle no case matching (optional if should be ignored)
}
Run Code Online (Sandbox Code Playgroud)

其次,看起来 pyo3 可以让您派生 enums,因为WriteValue显然这是一个内部特征,派生相应的 enum 是有意义的:

#[derive(FromPyObject)]
enum Writables {
    #[pyo3(transparent, annotation = "str")]
    String(String),
    #[pyo3(transparent, annotation = "float")]
    Float(f32),
    // put the other cases here
}
Run Code Online (Sandbox Code Playgroud)

然后您可以extract立即匹配所有变体(并单独处理“不支持的类型”)。

事实上,此时该特征可能是不必要的,除非它用于其他东西,否则您可以直接将您的write_value方法放在枚举上。

旁注:将 python float (这是一个双精度)提取为 anf32然后立即将其扩大为 anf64以将其写出来似乎......很奇怪。为什么不f64首先提取 an 呢?