我创建了一个 Rust 库,用于从 Python 中进行一些繁重的处理。它工作得相当好,但我留下的代码感觉臃肿且难以维护,所以我认为必须有更好的方法。我使用各种特征和枚举尝试了一些不同的选项,但很难做出任何真正的改进。我没有做过那么多 Rust,所以我猜测(并希望)我错过了一个好的、干净的解决方案。
rust 包基本上只是一个单一的核心结构,包含一些数据和相当多的实现方法。然后,它被一个 pyclass 结构包装以处理 Python 的接口。核心结构需要是通用的,或者至少最终的 python 类需要能够处理几种不同的数据类型。更复杂的是,我在其他 Rust 项目中使用了核心结构,所以我想将任何与 python 相关的东西排除在核心结构之外。
我最终使用了一系列巨大的宏来创建一些接口结构,一个来处理每种不同的数据类型。我发现这些宏很难使用,但我还没有想出简化或删除它们的方法。因此,如果有人对从这里去哪里有任何想法或提示,那将非常感激。
这是我的代码的一个极其简化的版本:
// main.rs
use pyo3::prelude::*;
pub mod core;
pub mod interface;
use interface::{FloatClass, IntClass, StrClass};
#[pymodule]
fn pyo3_test(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<FloatClass>()?;
m.add_class::<IntClass>()?;
m.add_class::<StrClass>()?;
Ok(())
}
// core.rs
pub struct Core<T> {
pub data: Vec<T>,
}
impl<T> Core<T> {
pub fn a(&self) {
println!("running: a");
}
pub fn b(&self) {
println!("running: b");
}
// lots more methods...
pub fn z(&self) {
println!("running: z");
}
}
// interface.rs
use pyo3::prelude::*;
use crate::core::Core;
macro_rules! create_interface {
($name: ident, $type: ident) => {
#[pyclass]
pub struct $name {
pub inner: Core<$type>,
}
#[pymethods]
impl $name {
#[new]
pub fn from_vector(data: Vec<$type>) -> Self {
Self { inner: Core { data: data } }
}
pub fn a(&self) {
self.inner.a()
}
pub fn b(&self) {
self.inner.b()
}
// need to implement each method here as well
// often using conversions to/from python types
pub fn z(&self) {
self.inner.z()
}
}
};
}
create_interface!(IntClass, i64);
create_interface!(FloatClass, f64);
create_interface!(StrClass, String);
接口中实现的方法显然远比本例中的复杂和独特,因此泛化接口方法会很困难。
感谢您的任何想法。