由于我有很强的弱类型编程背景,我对 rust 病非常、非常陌生,并与之斗争.

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

也许我可以 for each 潜在的提取类型链接匹配(如果第一个输出错误,请try 下一个),但我怀疑可能有更好的方法.也许我只是用一个错误的设计来解决这个问题.欢迎有任何见解.

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()
    }

推荐答案

这主要是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)
}

其次,pyo3似乎允许您使用derive enums,因为WriteValue显然是一个内部特征,因此可以推导相应的枚举:

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

然后,您可以一次将extractthat个变量匹配到所有变量(并分别处理"不支持的类型").

事实上,在这一点上,这个特性可能是不必要的,除非它用于其他东西,否则您可以直接在枚举上使用write_value方法.

旁注:将python浮点(双精度浮点)提取到f32,然后立即将其扩大到f64,以便写出它似乎...古怪的为什么不首先提取f64呢?

Rust相关问答推荐

关联类型(类型参数)命名约定

关于Rust 中回归的逻辑

为什么我不能从带有字符串的 struct 的引用迭代器中收集VEC<;&;str&>?

为什么允许我们将可变引用转换为不可变引用?

闭包不会发送,即使它只捕获发送变量

自定义结果枚举如何支持`?`/`FromResidual`?

RUST应用程序正在退出,错误代码为:(退出代码:0xc0000005,STATUS_ACCESS_VIOLATION)

在 Rust 中,在需要引用 self 的 struct 体方法中使用闭包作为 while 循环条件

详尽的匹配模式绑定

在 Rust 中忽略 None 值的正确样式

trait 对象指针的生命周期

为什么 for_each 在释放模式(cargo run -r)下比 for 循环快得多?

如何将参数传递给Rust 的线程?

LinkedList::drain_filter::drop 中 DropGuard 的作用是什么?

SDL2 没有在终端键上触发?

火箭整流罩、tokio-scheduler 和 cron 的生命周期问题

基于名称是否存在的条件编译

返回 &str 但不是 String 时,borrow 时间比预期长

为移动和借位的所有组合实现 Add、Sub、Mul、Div

如何使用 Axum/Tokio 记录和过滤请求?