假设我有一个像这样的 Rust 结构
struct X{...}
struct Y{
x:X
}
我希望能够编写访问 X
的 python 代码通过 Y
y = Y()
y.x.some_method()
在 PyO3 中实现它的最佳方法是什么?目前我做了两个包装类#[pyclass]
struct XWrapper{
x:X
}
#[pyclass]
struct YWrapper{
y:Y
}
#[pymethods]
impl YWrapper{
#[getter]
pub fn x(&self)->XWrapper{
XWrapper{x:self.y.clone()}
}
}
但是,这需要 clone()
.我宁愿要返回引用。我当然知道如果X
是 pyclass
,然后我可以轻松返回 PyRef
到它。但问题是X
和 Y
来自 Rust 库,我不能随意添加 #[pyclass]
给他们。
最佳答案
如果不重新调整界面,我认为您所说的不可能:
您的 XWrapper
拥有 x
和您的 Y
拥有其 x
以及。这意味着创建一个 XWrapper
将始终涉及克隆(或 new
)。
可以换吗XWrapper
以便它只包含对 x
的引用?不是真的,因为那需要给 XWrapper
生命周期注释,而 PyO3 afaik 不允许带有生命周期注释的 pyclasses。有道理,因为将对象传递给 python 会将它放在 python 堆上,此时 rust 失去对对象的控制。
所以,我们能做些什么?
一些想法:你真的需要暴露y
的组成结构吗?到python模块?仅仅因为它在 Rust 中的组织方式并不意味着它需要在 Python 中如此。您的 YWrapper
可以为python接口(interface)提供方法,在后台将请求转发到x
实例:
#[pymethods]
impl YWrapper{
pub fn some_method(&self) {
self.y.x.some_method();
}
}
对于严格遵守迪米特法则的人来说,这也是一个受欢迎的景象;)我在想其他聪明的方法。取决于一些细节如何
y.x
通过y
的方法访问和修改本身,可能可以添加一个字段 x: XWrapper
到 YWrapper
.然后你创建 XWrapper
(包括 y.x
的克隆)一次当 YWrapper
已创建,然后您可以返回对该 XWrapper
的引用。在您的 pub fn x
.当然,当 x
时,这会变得更加麻烦。通过 y
的方法频繁更改和更新...在某种程度上,这证明了 Python 的引用计数对象模型和 Rust 的所有权对象模型之间的冲突。 Rust 强制你不能随意弄乱对象,除非你是它们的所有者。
关于python - 返回对 PyO3 中成员字段的引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69665304/