Rust中postgres::Error错误处理失败,寻求解决方案
处理postgres::Error时的编译错误解决方法
我在处理postgres::Error时遇到问题,尝试用SqlState或DbError都没效果,怀疑postgres::error的错误处理有局限,或是自己遗漏了要点。以下是我的Rust代码:
extern crate postgres; use postgres::{Client, NoTls}; use postgres::error::Error as PgError; pub async fn get_metadata(client: &Client, db: String, schema: String) -> Result<serde_json::Value, PgError> { let query = r#" select row_to_json(Tb) as tbls from( . . . . WHERE table_schema=$1) Tb; "#; // Execute the query and collect the results let rows = client.query(query, &[&schema])?; // Assuming you expect only one row as a result if let Some(row) = rows.iter().next() { // Extract the JSON response from the "tbls" column let json_response: Option<serde_json::Value> = row.get(0); // You can now work with the JSON response match json_response { Some(json) => { return Ok(json); } None => { eprintln!("No JSON response found in the result."); // Return an error here return Err(_); } } } // Return an error if no row is found Err(PgError.into_source()) }
运行代码后出现以下编译错误:
error[E0061]: this function takes 1 argument but 0 arguments were supplied --> src/main.rs:64:9 | 64 | Err(PgError::into_source()) | ^^^^^^^^^^^^^^^^^^^^-- an argument of type `postgres::Error` is missing | note: method defined here --> /home/afidegnum/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-postgres-0.7.10/src/error/mod.rs:417:12 | 417 | pub fn into_source(self) -> Option<Box<dyn error::Error + Sync + Send>> { | ^^^^^^^^^^^ help: provide the argument | 64 | Err(PgError::into_source(/* postgres::Error */)) | ~~~~~~~~~~~~~~~~~~~~~~~ error[E0308]: mismatched types --> src/main.rs:64:9 | 64 | Err(PgError::into_source()) | --- ^^^^^^^^^^^^^^^^^^^^^^ expected `Error`, found `Option<Box<...>>` | | | arguments to this enum variant are incorrect | = note: expected struct `postgres::Error` found enum `Option<Box<(dyn std::error::Error + Send + Sync + 'static)>>` help: the type constructed contains `Option<Box<(dyn std::error::Error + Send + Sync + 'static)>>` due to the type of the argument passed --> src/main.rs:64:5 | 64 | Err(PgError::into_source()) | ^^^^----------------------^ | | | this argument influences the type of `Err` note: tuple variant defined here --> /home/afidegnum/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs:511:5 | 511 | Err(#[stable(feature = "rust1", since = "1.0.0")] E), | ^^^
尝试使用std::io::Error也无法解决该问题。
问题分析
编译错误的核心是两处误用:
into_source()方法调用错误:into_source()是postgres::Error实例的方法,需要通过具体错误对象调用,而非作为静态方法直接调用。而且它返回的是Option<Box<dyn Error + Sync + Send>>,和你函数声明的返回错误类型PgError不匹配。- 自定义错误返回缺失:当JSON值为空或无查询结果时,你没有构造合法的
PgError实例,而是用Err(_)这种无效写法。
解决方案
方案1:改用通用错误类型(推荐)
将函数返回的错误类型改为Box<dyn Error>,这样可以灵活返回任意实现了Error trait的错误,包括postgres原生错误和自定义错误:
extern crate postgres; use postgres::{Client, NoTls}; use postgres::error::Error as PgError; use std::error::Error; pub async fn get_metadata(client: &Client, db: String, schema: String) -> Result<serde_json::Value, Box<dyn Error>> { let query = r#" select row_to_json(Tb) as tbls from( . . . . WHERE table_schema=$1) Tb; "#; // 执行查询,postgres错误会自动转为Box<dyn Error> let rows = client.query(query, &[&schema])?; if let Some(row) = rows.iter().next() { let json_response: Option<serde_json::Value> = row.get(0); match json_response { Some(json) => Ok(json), None => { eprintln!("No JSON response found in the result."); // 返回自定义字符串错误 Err("No JSON response found in query result".into()) } } } else { // 返回自定义无结果错误 Err("No rows returned for the specified schema".into()) } }
方案2:构造PgError实例(若必须返回PgError)
如果业务要求必须返回PgError,可以手动构造DbError并包装成PgError:
extern crate postgres; use postgres::{Client, NoTls}; use postgres::error::{Error as PgError, DbError, SqlState}; pub async fn get_metadata(client: &Client, db: String, schema: String) -> Result<serde_json::Value, PgError> { let query = r#" select row_to_json(Tb) as tbls from( . . . . WHERE table_schema=$1) Tb; "#; let rows = client.query(query, &[&schema])?; if let Some(row) = rows.iter().next() { let json_response: Option<serde_json::Value> = row.get(0); match json_response { Some(json) => Ok(json), None => { eprintln!("No JSON response found in the result."); // 构造DbError实例 let db_err = DbError::new( SqlState::NO_DATA, "No JSON value found in result row".to_string(), None, vec![], ); Err(PgError::Db(db_err)) } } } else { // 构造无结果的DbError let db_err = DbError::new( SqlState::NO_DATA, "No rows returned for schema".to_string(), None, vec![], ); Err(PgError::Db(db_err)) } }
关键说明
into_source()是用来从已有的PgError实例中提取底层错误来源的,不是用来创建新错误的方法。- 通用错误类型
Box<dyn Error>在Rust错误处理中更灵活,适合大多数场景,避免被特定错误类型绑定。
内容的提问来源于stack exchange,提问作者alexander
相关产品推荐
相关产品推荐

