匹配多种可能的类型?
Matching multiple possible types?
由于我强大的弱类型编程背景,我对 Rust 非常非常陌生并且正在努力使用它。
下面的代码应该将通过 PYO3 从 Python 接收到的数据写入 XLSX 工作表。我只是不知道如何处理最后一个匹配项,因为“value”是 PyAny 类型的(也就是说,它的方法 extract 可以输出多种类型,例如 String、f32 等,我想要一个特定的行为取决于提取的类型)。
也许我可以为每个潜在的提取类型链接匹配(如果第一个输出错误,请尝试下一个),但我怀疑可能有更好的方法。也许我只是在用错误的设计来解决问题。欢迎任何见解。
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()
}
PyAny
可以试试downcast to any other Python type。我不精通 PyO3
,但我在这里看到的唯一方法是尝试向下转换为您支持的类型,否则可能会引发错误:
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
};
if let Ok(string) = value.downcast::<PyString> {
// handle pystring object
string.write_value(&mut worksheet, row_index.clone(), &col_idx -1, row_format)?;
...
} else if let Ok(int) = value.downcast::<PyInt> {
// handle pyint object
...
} else {
// error, or not supported
}
}
}
workbook.close()
}
这主要是一个 pyo3 API 问题,我不认为 pyo3 有 built-in“multiextract”,虽然我不是很熟悉它,所以它可能。
但是,首先,由于您不关心 Err
子句,您可以通过简单地链接 if let
语句来简化代码,它们是语法糖,但对于一元或二元布尔条件,它们真的很方便 e.g.
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
}
然后你可以extract
到that并一次匹配所有变体(并单独处理“不支持的类型”)。
事实上,此时 trait 可能是不必要的,除非它被用于其他东西,你可以直接在枚举上使用你的 write_value
方法。
side-note:将 python 浮点数(它是双精度数)提取到 f32
然后立即将其扩大到 f64
以便将其写出来... 奇怪的。为什么不首先提取 f64
?
由于我强大的弱类型编程背景,我对 Rust 非常非常陌生并且正在努力使用它。
下面的代码应该将通过 PYO3 从 Python 接收到的数据写入 XLSX 工作表。我只是不知道如何处理最后一个匹配项,因为“value”是 PyAny 类型的(也就是说,它的方法 extract 可以输出多种类型,例如 String、f32 等,我想要一个特定的行为取决于提取的类型)。
也许我可以为每个潜在的提取类型链接匹配(如果第一个输出错误,请尝试下一个),但我怀疑可能有更好的方法。也许我只是在用错误的设计来解决问题。欢迎任何见解。
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()
}
PyAny
可以试试downcast to any other Python type。我不精通 PyO3
,但我在这里看到的唯一方法是尝试向下转换为您支持的类型,否则可能会引发错误:
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
};
if let Ok(string) = value.downcast::<PyString> {
// handle pystring object
string.write_value(&mut worksheet, row_index.clone(), &col_idx -1, row_format)?;
...
} else if let Ok(int) = value.downcast::<PyInt> {
// handle pyint object
...
} else {
// error, or not supported
}
}
}
workbook.close()
}
这主要是一个 pyo3 API 问题,我不认为 pyo3 有 built-in“multiextract”,虽然我不是很熟悉它,所以它可能。
但是,首先,由于您不关心 Err
子句,您可以通过简单地链接 if let
语句来简化代码,它们是语法糖,但对于一元或二元布尔条件,它们真的很方便 e.g.
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
}
然后你可以extract
到that并一次匹配所有变体(并单独处理“不支持的类型”)。
事实上,此时 trait 可能是不必要的,除非它被用于其他东西,你可以直接在枚举上使用你的 write_value
方法。
side-note:将 python 浮点数(它是双精度数)提取到 f32
然后立即将其扩大到 f64
以便将其写出来... 奇怪的。为什么不首先提取 f64
?