如何在不使用嵌套匹配和解包的情况下从查询中获取值



我想运行一些 MySQL 查询,但处理不同类型的错误,从Error::IoError检查一些超时,到自定义错误类型NotMatching(String)当查询返回的项目不匹配时,跟进其他问题,我想出了这个:

use std::{error, fmt};
#[derive(Debug)]
pub enum Error {
MySQL(mysql::Error),
NotMatching(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::MySQL(ref err) => err.fmt(f),
Error::NotMatching(ref err) => err.fmt(f),
}
}
}
impl error::Error for Error {}
impl From<mysql::Error> for Error {
fn from(err: mysql::Error) -> Self {
Error::MySQL(err)
}
}
pub struct Queries {
pool: mysql::Pool,
}
pub fn new(pool: mysql::Pool) -> Queries {
return Queries { pool: pool };
}
impl Queries {
pub fn test_rw(&self, now: u64) -> Result<(), Error> {
let pool = &self.pool.clone();
// create table
pool.prep_exec("CREATE TABLE IF NOT EXISTS dbpulse_rw (id INT NOT NULL, t INT(11) NOT NULL, PRIMARY KEY(id))", ())?;
// write into table
let mut stmt = pool
.prepare("INSERT INTO dbpulse_rw (id, t) VALUES (1, ?) ON DUPLICATE KEY UPDATE t=?")?;
stmt.execute((now, now))?;
let rows = pool.prep_exec("SELECT t FROM dbpulse_rw WHERE id=1", ())?;
for row in rows {
match row {
Ok(row) => match mysql::from_row_opt::<u64>(row) {
Ok(row) => {
if now != row {
return Result::Err(Error::NotMatching("no matching...".into()));
}
}
Err(e) => {
return Result::Err(Error::MySQL(e.into()));
}
},
Err(e) => {
return Result::Err(Error::MySQL(e));
}
}
}
Ok(())
}
}

它有效,但想知道是否有更好(干净)的方法,可能使用and_thenmap来减少从查询中获取单个值的代码,我主要指的是这部分:

let rows = pool.prep_exec("SELECT t FROM dbpulse_rw WHERE id=1", ())?;
for row in rows {
match row {
Ok(row) => match mysql::from_row_opt::<u64>(row) {
Ok(row) => {
if now != row {
return Result::Err(Error::NotMatching("no matching...".into()));
}
}
Err(e) => {
return Result::Err(Error::MySQL(e.into()));
}
},
Err(e) => {
return Result::Err(Error::MySQL(e));
}
}
}

我想防止恐慌并更好地处理错误,这就是为什么我省略了unwrap的使用,但希望有一些关于如何改进的例子。

?map_err应该有助于摆脱大部分嵌套。素描:

let rows = pool.prep_exec("SELECT t FROM dbpulse_rw WHERE id=1", ())?;
for row in rows {
let row = row.map_err(Error::MySQL)?;
let row = mysql::from_row_opt::<u64>(row).map_err(|e| Error::MySQL(e.into()))?;
if now != row {
return Err(Error::NotMatching("no matching...".into()));
}
}

最新更新