PyO3中自定义结构体的向量

8

我是一个Rust和PyO3的新手(来自Python),对于更有经验的人可能很明显。

我在PyO3中声明了一个pyclass结构体。

#[pyclass]
struct Block {
    start: i32,
    stop: i32,
}

然后我在一个接受 Block 向量并输出整数向量的 Rust 函数中使用 Block(签名如下)

#[pyfunction]
fn from_blocks(block_list: Vec<Block>) -> Vec<i32>

当我使用nightly-x86_64-apple-darwin编译时,出现以下错误:

#[pyfunction]
^^^^^^^^^^^^^ the trait `pyo3::FromPyObject<'_>` is not implemented for `std::vec::Vec<Block>`

我该如何解决这个问题?

编辑: Caio是正确的。我在追溯错误时犯了一个错误。 之前我写道:

然后我在一个接受整数向量并输出Block向量的Rust函数中使用了Block(下面是签名)

#[pyfunction]
fn to_blocks(list: Vec<i32>) -> Vec<Block>

但实际上有问题的函数是:

#[pyfunction]
fn from_blocks(block_list: Vec<Block>) -> Vec<i32>

我已经更新了问题,使其更加清晰明了。


1
抱歉让大家感到困惑。@Caio 直觉地发现有问题的函数具有相反的签名。因此,我已经更新了问题。 - kentwait
3个回答

5
FromPyObject旨在用于从Python世界中提取类型。这就是为什么我认为您试图编写fn to_blocks(list: Vec<Block>) -> Vec<i32>而不是fn to_blocks(list: Vec<i32>) -> Vec<Block>。如果是这种情况,让我们深入到实现链中。 FromPyObject为实现了PyTryFrom的任何&T提供了默认实现,而PyTryFrom为实现了PyTypeInfo的任何T提供了默认实现。 [pyclass]根据impl_class方法实现了PyObjectAllocPyObjectWithFreeList,两个特征都有PyTypeInfo特征绑定。因此,您的类/结构将与引用一起正常工作,例如:
#[pyfunction]
fn to_blocks(list: Vec<&Block>) -> Vec<i32>

您可以在官方文档中看到这个简要的解释。

FromPyObject 是由多种类型实现的,可以从 Python 对象引用中提取。


一个名为to_blocks的函数为什么会以块向量作为输入并返回整数向量? - interjay
尽管函数名为 fn to_blocks(list: Vec<i32>) -> Vec<Block>,但它可以顺利编译通过,即使出现编译错误,也会是不同的错误。 - Caio
1
这个问题中他给出的编译错误只是因为自定义派生不足以使本地拥有的类型用于函数参数。这就是为什么我建议他可能写错了代码,如果是这种情况,上述答案的措施将是必要的。如果我表达不清楚,我可以适当编辑我的帖子。 - Caio
1
@interjay,@caio抱歉让你们感到困惑。我认为@caio已经明白了,因为我有一个fn to_blocks,所以有一个相反的函数来执行反向操作,这就是导致错误的原因。 - kentwait
谢谢kentwait。@interjay提出了一些重要的声明,现在已经修复。 - Caio
显示剩余3条评论

0

看起来pyfunction属性生成的代码需要返回类型实现FromPyObject特质。虽然有一个FromPyObject for Vec<T> where T: FromPyObject的通用实现,但是看起来为您的Block类型生成的pyclass属性代码不包括FromPyObject的实现。

由于我对PyO3除了刚刚查看其API文档以验证答案之外并不熟悉,所以我不确定如何最好地获得FromPyObject的实现——也许有一个derive可以实现它?


0
你使用的是哪个版本的PyO3? 你的代码在我的0.5.3和0.6.0-alpha.1上运行良好。
由于我无法测试这个问题,但我猜测你需要返回一个PyResult:
#[pyfunction]
fn to_blocks(list: Vec<i32>) -> PyResult<Vec<Block>>

1
#[pyclass]Block 实现了 IntoPyObject/ToPyObject 接口,这就是它能正常工作的原因。原始代码应该改为 fn to_blocks(list: Vec<Block>) -> Vec<i32> - Caio
@Caio我有些困惑 - 既然OP的代码能够工作,为什么还需要其他解释呢? - Chronial
因为他给出的错误信息与将Block用作输入参数时得到的错误信息相同。为了确保,我认为最好等待他对此事的回复。 - Caio
1
@Caio 你说得对,我追踪到错误是由于错误的函数引起的。这个错误源自于 fn from_blocks(block_list: Vec<Block>) -> Vec<i32> - kentwait
@kentwait 谢谢 =) - Caio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接