[英]How can I access a Rust Iterator from Python using PyO3?
我對 Rust 很陌生,我的第一個“嚴肅”項目涉及使用 PyO3 為小型 Rust 庫編寫 Python 包裝器。 這基本上很輕松,但我正在努力研究如何將 Rust Vec
上的惰性迭代器暴露給 Python 代碼。
到目前為止,我一直在收集迭代器產生的值並返回一個列表,這顯然不是最好的解決方案。 這是一些說明我的問題的代碼:
use pyo3::prelude::*;
// The Rust Iterator, from the library I'm wrapping.
pub struct RustIterator<'a> {
position: usize,
view: &'a Vec<isize>
}
impl<'a> Iterator for RustIterator<'a> {
type Item = &'a isize;
fn next(&mut self) -> Option<Self::Item> {
let result = self.view.get(self.position);
if let Some(_) = result { self.position += 1 };
result
}
}
// The Rust struct, from the library I'm wrapping.
struct RustStruct {
v: Vec<isize>
}
impl RustStruct {
fn iter(&self) -> RustIterator {
RustIterator{ position: 0, view: &self.v }
}
}
// The Python wrapper class, which exposes the
// functions of RustStruct in a Python-friendly way.
#[pyclass]
struct PyClass {
rust_struct: RustStruct,
}
#[pymethods]
impl PyClass {
#[new]
fn new(v: Vec<isize>) -> Self {
let rust_struct = RustStruct { v };
Self{ rust_struct }
}
// This is what I'm doing so far, which works
// but doesn't iterate lazily.
fn iter(&self) -> Vec<isize> {
let mut output_v = Vec::new();
for item in self.rust_struct.iter() {
output_v.push(*item);
}
output_v
}
}
我試圖用 Python 包裝器包裝RustIterator
class,但我不能使用 PyO3 的#[pyclass]
proc。 帶有生命周期參數的宏。 我查看了pyo3::types::PyIterator
但這看起來像是一種從 Rust 訪問 Python 迭代器的方法,而不是相反。
如何在RustStruct.v
中通過 RustStruct.v 訪問惰性迭代器? 可以安全地假設Vec
中包含的類型始終派生Copy
和Clone
,並且需要 Python 端的一些代碼的答案是可以的(但不太理想)。
您可以將RustIterator
pyclass
,然后使用 rust 迭代器本身實現適當的特征( PyIterProtocol
)。
未經測試,但類似:
#[pyclass]
pub struct RustIterator<'a> {
position: usize,
view: &'a Vec<isize>
}
impl<'a> Iterator for RustIterator<'a> {
type Item = &'a isize;
fn next(&mut self) -> Option<Self::Item> {
let result = self.view.get(self.position);
if let Some(_) = result { self.position += 1 };
result
}
}
#[pyproto]
impl PyIterProtocol for Iter {
fn __next__(mut slf: PyRefMut<Self>) -> IterNextOutput<usize, &'static str> {
match self.next() {
Some(value) => IterNextOutput::Yield(value),
None => IterNextOutput::Return("Ended")
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.