如何更改一个值,使其在 Rust 中没有静态生命周期
How to change a value so that it doesn't have static lifetime in Rust
我有以下使用 PyO3 调用 python 函数并获得结果的函数(在本例中,int
被分配给 i32
):
fn run_python<'a, T: FromPyObject<'a> + Clone>(func_name: &str) -> Result<T, ()> {
Python::with_gil(|py| {
let pyapi = match py.import("pyapi") {
Ok(v) => v,
Err(e) => { e.print_and_set_sys_last_vars(py); return Err(()) },
};
let locals = [("pyapi", pyapi)].into_py_dict(py);
let eval_result: PyResult<&PyAny> = py.eval("pyapi.{}(**kwargs)", None, Some(&locals));
let wrapped_obj: &PyAny = match eval_result {
Ok(v) => v,
Err(e) => { e.print_and_set_sys_last_vars(py); return Err(()) },
};
let unwrapped_result: PyResult<T> = wrapped_obj.extract();
match unwrapped_result {
Ok(v) => return Ok(v.clone()),
Err(e) => return Err(()),
};
})
}
当我尝试编译时,出现以下错误:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'p` due to conflicting requirements
--> src\bin\launch.rs:89:30
|
89 | let eval_result = py.eval("pyapi.{}(**kwargs)", None, Some(&locals));
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 82:22...
--> src\bin\launch.rs:82:22
|
82 | Python::with_gil(|py| {
| ______________________^
83 | | let pyapi = match py.import("pyapi") {
84 | | Ok(v) => v,
85 | | Err(e) => { e.print_and_set_sys_last_vars(py); return Err(()) },
... |
101 | | };
102 | | })
| |_____^
note: ...so that the types are compatible
--> src\bin\launch.rs:89:30
|
89 | let eval_result = py.eval("pyapi.{}(**kwargs)", None, Some(&locals));
| ^^^^
= note: expected `pyo3::Python<'_>`
found `pyo3::Python<'_>`
note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 81:15...
--> src\bin\launch.rs:81:15
|
81 | fn run_python<'a, T: FromPyObject<'a> + Clone>(func_name: &str) -> Result<T, ()> {
| ^^
note: ...so that the types are compatible
--> src\bin\launch.rs:96:57
|
96 | let unwrapped_result: PyResult<T> = wrapped_obj.extract();
| ^^^^^^^
= note: expected `pyo3::FromPyObject<'_>`
found `pyo3::FromPyObject<'a>`
我是 Rust 的新手,可能正在做一些愚蠢的事情(很可能是 X/Y 问题)。我怎样才能从 py.eval
中得到一个没有与 python 解释器相关的生命周期的值(这就是我假设在这里发生的事情)?
Ry 建议的修复似乎很有效。使用 for<'p>
可以让编译器推迟对生命周期的评估,直到在处理调用 .extract()
的代码时需要它。生命周期 'p
不需要在函数的通用参数列表中指定。此外,不需要 Clone
绑定。
fn run_python<T>(func_name: &str) -> Result<T, ()>
where
T: for<'p> FromPyObject<'p>,
{
let guard = Python::acquire_gil();
let py = guard.python();
match || -> _ { // try...
let pyapi = py.import("pyapi")?; // throw...
let locals = [("pyapi", pyapi)].into_py_dict(py);
py.eval(&format!("pyapi.{}(**kwargs)", func_name),
None,
Some(&locals))?.extract()
}() { // catch...
Err(e) => {
// Error handling specific to Pyo3.
e.print_and_set_sys_last_vars(py);
// Return the error type spec'd in the fn signature.
Err(())
},
Ok(obj) => Ok(obj),
}
}
此方法的唯一限制是 .extract()
转换到的类型需要不依赖于它从中转换的类型的生命周期。例如,如果 run_python()
可以 return 字符串列表,这是可能的:
let values: Vec<String> = run_python("make_string_list").unwrap(); // OK.
但是这会产生与生命周期相关的编译器错误,尽管 .extract()
能够在正确的条件下产生这种类型:
let values: Vec<&str> = run_python("make_string_list").unwrap(); // Error.
如果 run_python()
需要能够生成依赖于生命周期的值,那么一个解决方案可能是让调用者获取 GIL,并传入一个 Python
实例。该函数可能如下所示:
fn run_python<'p, T>(func_name: &str, py: Python<'p>) -> PyResult<T>
where
T: FromPyObject<'p>,
{
let pyapi = py.import("pyapi")?;
let locals = [("pyapi", pyapi)].into_py_dict(py);
py.eval(&format!("pyapi.{}(**kwargs)", func_name),
None,
Some(&locals))?.extract()
}
在我意识到使用 for<>
的建议是最佳选择之前,我开始写另一个答案。我假设 return 值对 GIL 有一定的依赖性,但是 .extract()
returns 类型不依赖于 GIL。
在之前的回答中,我提出了一些方法来处理 Python 需要在 GIL 生命周期之外保留的对象。这涉及使用 .to_object(py)
将 GIL 依赖类型转换为 GIL 独立类型,并在需要时使用 .cast_as::<PyType>(py)
等方法再次返回。
我有以下使用 PyO3 调用 python 函数并获得结果的函数(在本例中,int
被分配给 i32
):
fn run_python<'a, T: FromPyObject<'a> + Clone>(func_name: &str) -> Result<T, ()> {
Python::with_gil(|py| {
let pyapi = match py.import("pyapi") {
Ok(v) => v,
Err(e) => { e.print_and_set_sys_last_vars(py); return Err(()) },
};
let locals = [("pyapi", pyapi)].into_py_dict(py);
let eval_result: PyResult<&PyAny> = py.eval("pyapi.{}(**kwargs)", None, Some(&locals));
let wrapped_obj: &PyAny = match eval_result {
Ok(v) => v,
Err(e) => { e.print_and_set_sys_last_vars(py); return Err(()) },
};
let unwrapped_result: PyResult<T> = wrapped_obj.extract();
match unwrapped_result {
Ok(v) => return Ok(v.clone()),
Err(e) => return Err(()),
};
})
}
当我尝试编译时,出现以下错误:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'p` due to conflicting requirements
--> src\bin\launch.rs:89:30
|
89 | let eval_result = py.eval("pyapi.{}(**kwargs)", None, Some(&locals));
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 82:22...
--> src\bin\launch.rs:82:22
|
82 | Python::with_gil(|py| {
| ______________________^
83 | | let pyapi = match py.import("pyapi") {
84 | | Ok(v) => v,
85 | | Err(e) => { e.print_and_set_sys_last_vars(py); return Err(()) },
... |
101 | | };
102 | | })
| |_____^
note: ...so that the types are compatible
--> src\bin\launch.rs:89:30
|
89 | let eval_result = py.eval("pyapi.{}(**kwargs)", None, Some(&locals));
| ^^^^
= note: expected `pyo3::Python<'_>`
found `pyo3::Python<'_>`
note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 81:15...
--> src\bin\launch.rs:81:15
|
81 | fn run_python<'a, T: FromPyObject<'a> + Clone>(func_name: &str) -> Result<T, ()> {
| ^^
note: ...so that the types are compatible
--> src\bin\launch.rs:96:57
|
96 | let unwrapped_result: PyResult<T> = wrapped_obj.extract();
| ^^^^^^^
= note: expected `pyo3::FromPyObject<'_>`
found `pyo3::FromPyObject<'a>`
我是 Rust 的新手,可能正在做一些愚蠢的事情(很可能是 X/Y 问题)。我怎样才能从 py.eval
中得到一个没有与 python 解释器相关的生命周期的值(这就是我假设在这里发生的事情)?
Ry 建议的修复似乎很有效。使用 for<'p>
可以让编译器推迟对生命周期的评估,直到在处理调用 .extract()
的代码时需要它。生命周期 'p
不需要在函数的通用参数列表中指定。此外,不需要 Clone
绑定。
fn run_python<T>(func_name: &str) -> Result<T, ()>
where
T: for<'p> FromPyObject<'p>,
{
let guard = Python::acquire_gil();
let py = guard.python();
match || -> _ { // try...
let pyapi = py.import("pyapi")?; // throw...
let locals = [("pyapi", pyapi)].into_py_dict(py);
py.eval(&format!("pyapi.{}(**kwargs)", func_name),
None,
Some(&locals))?.extract()
}() { // catch...
Err(e) => {
// Error handling specific to Pyo3.
e.print_and_set_sys_last_vars(py);
// Return the error type spec'd in the fn signature.
Err(())
},
Ok(obj) => Ok(obj),
}
}
此方法的唯一限制是 .extract()
转换到的类型需要不依赖于它从中转换的类型的生命周期。例如,如果 run_python()
可以 return 字符串列表,这是可能的:
let values: Vec<String> = run_python("make_string_list").unwrap(); // OK.
但是这会产生与生命周期相关的编译器错误,尽管 .extract()
能够在正确的条件下产生这种类型:
let values: Vec<&str> = run_python("make_string_list").unwrap(); // Error.
如果 run_python()
需要能够生成依赖于生命周期的值,那么一个解决方案可能是让调用者获取 GIL,并传入一个 Python
实例。该函数可能如下所示:
fn run_python<'p, T>(func_name: &str, py: Python<'p>) -> PyResult<T>
where
T: FromPyObject<'p>,
{
let pyapi = py.import("pyapi")?;
let locals = [("pyapi", pyapi)].into_py_dict(py);
py.eval(&format!("pyapi.{}(**kwargs)", func_name),
None,
Some(&locals))?.extract()
}
在我意识到使用 for<>
的建议是最佳选择之前,我开始写另一个答案。我假设 return 值对 GIL 有一定的依赖性,但是 .extract()
returns 类型不依赖于 GIL。
在之前的回答中,我提出了一些方法来处理 Python 需要在 GIL 生命周期之外保留的对象。这涉及使用 .to_object(py)
将 GIL 依赖类型转换为 GIL 独立类型,并在需要时使用 .cast_as::<PyType>(py)
等方法再次返回。