0

我正在尝试在 pyo3 的帮助下打开并写入我将从 python 调用的 Rust 库中的数据库。如果发生错误,我想引发一个可以在调用 Python 进程中捕获的异常,但是我在终止执行和引发错误时遇到了困难。

use rusqlite::{Connection};
use rusqlite::NO_PARAMS;
use pyo3::{Python, wrap_pyfunction};
use pyo3::exceptions::PyIOError;

#[pyfunction]
fn do_something(_py: Python) -> PyResult<u32> {
    match Connection::open("database.sql") {
        Ok(t) => conn = t,
        Err(e) => {
            let gil = Python::acquire_gil();
            let py = gil.python();
            let error_message = format!("Unable to open database! {}", e.to_string());
            PyIOError::new_err(error_message).restore(py)
        }
    };
    
    match conn.execute(
        "create table if not exists cats (
            id              INTEGER PRIMARY KEY,
            name            TEXT NOT NULL,
        )",
        NO_PARAMS,
    ) {
        Ok(_t) => (),
        Err(e) => {
            let gil = Python::acquire_gil();
            let py = gil.python();
            let error_message = format!("Unable to open database! {}", e.to_string());
            PyIOError::new_err(error_message).restore(py)
        }
    }
    Ok(0)

我的理解是,通过restore在对象上调用函数PyIOError会引发错误,但是,我一定是误解了,因为编译器似乎认为它是一种conn未初始化的可能性:

error[E0381]: borrow of possibly-uninitialized variable: `conn`

18  |             match conn.execute(
    |                   ^^^^ use of possibly-uninitialized `conn`

这里有什么合适的方法?

4

1 回答 1

1

首先,你Ok(t) = conn = t失败了,因为你没有定义conn. 所以在match添加之前let conn;。或者,您也可以将匹配结果分配给conn.

其次,您仍然需要返回一个Err.

#[pyfunction]
fn do_something(_py: Python) -> PyResult<u32> {
    let conn = match Connection::open("database.sql") {
        Ok(t) => t,
        Err(e) => {
            let gil = Python::acquire_gil();
            let py = gil.python();
            let error_message = format!("Unable to open database! {}", e.to_string());
            PyIOError::new_err(error_message).restore(py);
            return Err(PyErr::fetch(py));
        }
    };

    match conn.execute(
        "create table if not exists cats (
            id              INTEGER PRIMARY KEY,
            name            TEXT NOT NULL,
        )",
        NO_PARAMS,
    ) {
        Ok(_t) => (),
        Err(e) => {
            let gil = Python::acquire_gil();
            let py = gil.python();
            let error_message = format!("Unable to open database! {}", e.to_string());
            PyIOError::new_err(error_message).restore(py);
            return Err(PyErr::fetch(py));
        }
    }
    Ok(0)
}

自从我使用 PyO3 以来已经有一段时间了。但除非我记错了,否则你可以删除restore()也只是返回Err并让 PyO3 处理其余的。

#[pyfunction]
fn do_something(_py: Python) -> PyResult<u32> {
    let conn = match Connection::open("database.sql") {
        Ok(t) => t,
        Err(e) => {
            let error_message = format!("Unable to open database! {}", e.to_string());
            return Err(PyIOError::new_err(error_message));
        }
    };

    match conn.execute(
        "create table if not exists cats (
            id              INTEGER PRIMARY KEY,
            name            TEXT NOT NULL,
        )",
        NO_PARAMS,
    ) {
        Ok(_t) => (),
        Err(e) => {
            let error_message = format!("Unable to open database! {}", e.to_string());
            return Err(PyIOError::new_err(error_message));
        }
    }
    Ok(0)
}
于 2021-01-08T14:36:15.030 回答