Return 引用 PyO3 中的成员字段
Return reference to member field in PyO3
假设我有一个这样的 Rust 结构
struct X{...}
struct Y{
x:X
}
我希望能够编写 python 通过 Y
访问 X
的代码
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()
。我宁愿return参考。我当然知道,如果 X
是 pyclass
,那么我可以很容易地 return 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 接口提供方法,在后台将请求转发给 x
实例:
#[pymethods]
impl YWrapper{
pub fn some_method(&self) {
self.y.x.some_method();
}
}
对于 Demeter 法则的严格拥护者来说,这也是一个受欢迎的景象 ;)
我正在想其他聪明的方法。根据 y
本身的方法如何访问和修改 y.x
的一些细节,可能可以将字段 x: XWrapper
添加到 YWrapper
。然后在创建 YWrapper
时创建 XWrapper
(包括 y.x
的克隆)一次,从那时起,您可以 return 引用 XWrapper
你的 pub fn x
。当然,当 x
通过 y
...
的方法频繁更改和更新时,这会变得更加麻烦
在某种程度上,这证明了 Python 的引用计数对象模型和 Rust 的所有权对象模型之间的冲突。 Rust 强制你不能随意乱用对象,除非你是它们的所有者。
假设我有一个这样的 Rust 结构
struct X{...}
struct Y{
x:X
}
我希望能够编写 python 通过 Y
X
的代码
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()
。我宁愿return参考。我当然知道,如果 X
是 pyclass
,那么我可以很容易地 return 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 接口提供方法,在后台将请求转发给 x
实例:
#[pymethods]
impl YWrapper{
pub fn some_method(&self) {
self.y.x.some_method();
}
}
对于 Demeter 法则的严格拥护者来说,这也是一个受欢迎的景象 ;)
我正在想其他聪明的方法。根据 y
本身的方法如何访问和修改 y.x
的一些细节,可能可以将字段 x: XWrapper
添加到 YWrapper
。然后在创建 YWrapper
时创建 XWrapper
(包括 y.x
的克隆)一次,从那时起,您可以 return 引用 XWrapper
你的 pub fn x
。当然,当 x
通过 y
...
在某种程度上,这证明了 Python 的引用计数对象模型和 Rust 的所有权对象模型之间的冲突。 Rust 强制你不能随意乱用对象,除非你是它们的所有者。