3

假设我有一个像这样的 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是 a pyclass,那么我可以很容易地回到PyRef它。但问题是它X来自Y一个 Rust 库,我不能傻傻地添加#[pyclass]到它们中。

4

1 回答 1

2

如果不对界面进行一些重新调整,我认为您所说的内容是不可能的:

XWrapper 拥有x,你也Y拥有它x。这意味着创建 aXWrapper将始终涉及克隆(或 a new)。

我们可以改变XWrapper它只包含对 a 的引用x吗?不是真的,因为这需要给出XWrapper生命周期注释,而 PyO3 afaik 不允许带有生命周期注释的 pyclasses。有道理,因为将对象传递给 python 会将其放在 python 堆上,此时 rust 会失去对对象的控制。

那么我们做些什么呢?

一些想法:你真的需要将组合结构暴露y给python模块吗?仅仅因为它在 Rust 中的组织方式并不意味着它在 Python 中必须是这种方式。您YWrapper可以为 python 接口提供方法,在后台将请求转发给x实例:

#[pymethods]
impl YWrapper{
   pub fn some_method(&self) {
     self.y.x.some_method();
   }
}

对于德墨忒耳法则的严格追随者来说,这也是一个受欢迎的景象;)

我正在尝试其他聪明的方法。根据自身y.x的方法如何访问和修改的一些细节,y可以将一个字段添加x: XWrapperYWrapper. 然后在创建时创建XWrapper(包括 的克隆y.xYWrapper,从那时起,您可以XWrapperpub fn x. 当然,当通过...x的方法频繁更改和更新时,这会变得更加麻烦。y

在某种程度上,这证明了 Python 的引用计数对象模型和 Rust 的所有权对象模型之间的冲突。Rust 强制你不能随意乱搞对象,除非你是它们的所有者。

于 2021-10-21T18:43:42.407 回答