当前位置: 首页 > news >正文

百度商桥怎么绑定网站营销型网站更受用户欢迎的原因是

百度商桥怎么绑定网站,营销型网站更受用户欢迎的原因是,网站建设设计公,网站建设案例步骤随着项目的进展&#xff0c;关于Rust的故事又翻开了新的一页&#xff0c;今天来到了服务器端的开发场景&#xff0c;发现错误处理中的错误类型转换有必要分享一下。 Rust抽象出来了Result<T,E>&#xff0c;T是返回值的类型&#xff0c;E是错误类型。只要函数的返回值的类…

随着项目的进展,关于Rust的故事又翻开了新的一页,今天来到了服务器端的开发场景,发现错误处理中的错误类型转换有必要分享一下。
Rust抽象出来了Result<T,E>,T是返回值的类型,E是错误类型。只要函数的返回值的类型被定义为Resut<T,E>,那么作为开发人员就有责任来处理调用这个函数可能发生的错误。通过Result<T,E>,Rust其实给开发人员指明了一条错误处理的道路,使代码更加健壮。

场景

  1. 服务器端处理api请求的框架:Rocket
  2. 服务器端处理数据持久化的框架:tokio_postgres

在api请求的框架中,我把返回类型定义成了Result<T, rocket::response::status::Custom\<String>>,即错误类型是rocket::response::status::Custom\<String>
在tokio_postgres中,直接使用tokio_postgres::error::Error

即如果要处理错误,就必须将tokio_postgres::error::Error转换成rocket::response::status::Custom\<String>。那么我们从下面的原理开始,逐一领略Rust的错误处理方式,通过对比找到最合适的方式吧。

原理

对错误的处理,Rust有3种可选的方式

  1. 使用match
  2. 使用if let
  3. 使用map_err

下面我结合场景,逐一演示各种方式是如何处理错误的。
下面的代码中涉及到2个模块(文件)。/src/routes/notes.rs是路由层,负责将api请求导向合适的service。/src/services/note_books.rs是service层,负责业务逻辑和数据持久化的处理。这里的逻辑也很简单,就是route层调用service层,将数据写入到数据库中。

使用match

src/routes/notes.rs

#[post("/api/notes", format = "application/json", data = "<note>")]
pub async fn post_notes(note: Json<Note>) -> Result<(), rocket::response::status::Custom<String>> {insert_or_update_note(&note.into_inner()).await
}

/src/services/note_book.rs

pub async fn insert_or_update_note(note: &Note,
) -> Result<(), rocket::response::status::Custom<String>> {let (client, connection) = match connect("host=localhost dbname=notes_db user=postgres port=5432",NoTls,).await{Ok(res) => res,Err(err) => {return Err(rocket::response::status::Custom(rocket::http::Status::ExpectationFailed,format!("{}", err),));}};...match client.execute("insert into notes (id, title, content) values($1, $2, $3);",&[&get_system_seconds(), &note.title, &note.content],).await{Ok(res) => Ok(()),Err(err) => Err(rocket::response::status::Custom(rocket::http::Status::ExpectationFailed,format!("{}", err),)),}
}

通过上面的代码我们可以读出一下内容:

  1. 在service层定义了route层相同的错误类型
  2. 在service层将持久层的错误转换成了route层的错误类型
  3. 使用match的代码量还是比较大

使用if let

/src/services/note_book.rs

pub async fn insert_or_update_note(note: &Note,
) -> Result<(), rocket::response::status::Custom<String>> {if let Ok((client, connection)) = connect("host=localhost dbname=notes_db user=postgres port=5432",NoTls,).await{...if let Ok(res) = client.execute("insert into notes (id, title, content) values($1, $2, $3);",&[&get_system_seconds(), &note.title, &note.content],).await{Ok(())} else {Err(rocket::response::status::Custom(rocket::http::Status::ExpectationFailed,format!("{}", "unknown error"),))}} else {Err(rocket::response::status::Custom(rocket::http::Status::ExpectationFailed,format!("{}", "unknown error"),))}
}

src/routes/notes.rs

#[post("/api/notes", format = "application/json", data = "<note>")]
pub async fn post_notes(note: Json<Note>) -> Result<(), rocket::response::status::Custom<String>> {insert_or_update_note(&note.into_inner()).await
}

使用了if let ...,代码更加的别扭,并且在else分支中,拿不到具体的错误信息。

其实,不难看出,我们的目标是将api的请求,经过route层和service层,将数据写入到数据中。但这其中的错误处理代码的干扰就特别大,甚至要有逻辑嵌套现象。这种代码的已经离初衷比较远了,是否有更加简洁的方式,使代码能够最大限度的还原逻辑本身,把错误处理的噪音降到最低呢?
答案肯定是有的。那就是map_err

map_err

map_err是Result上的一个方法,专门用于错误的转换。下面的代码经过了map_err的改写,看上去是不是清爽了不少啊。
/src/services/note_book.rs

pub async fn insert_or_update_note(note: &Note,
) -> Result<(), rocket::response::status::Custom<String>> {let (client, connection) = connect("host=localhost dbname=notes_db user=postgres port=5432",NoTls,).await.map_err(|err| {rocket::response::status::Custom(rocket::http::Status::ExpectationFailed,format!("{}", err),)})?;...let _ = client.execute("insert into notes (id, title, content) values($1, $2, $3);",&[&get_system_seconds(), &note.title, &note.content],).await.map_err(|err| {rocket::response::status::Custom(rocket::http::Status::ExpectationFailed,format!("{}", err),)})?;Ok(())
}

src/routes/notes.rs

#[post("/api/notes", format = "application/json", data = "<note>")]
pub async fn post_notes(note: Json<Note>) -> Result<(), rocket::response::status::Custom<String>> {insert_or_update_note(&note.into_inner()).await
}

经过map_err改写后的代码,代码的逻辑流程基本上还原了逻辑本身,但是map_err要额外占4行代码,且错误对象的初始化代码存在重复。在实际的工程项目中,service层的处理函数可能是成百上千,如果再乘以4,那多出来的代码量也不少啊,这会给后期的维护带来不小的压力。

那是否还有改进的空间呢?答案是Yes。
Rust为我们提供了From<T> trait,用于类型转换。它定义了从一种类型T到另一种类型Self的转换方法。我觉得这是Rust语言设计亮点之一。
但是,Rust有一个显示,即实现From<T> trait的结构,必须有一个在当前的crate中,也就是说我们不能直接通过From<T>来实现从tokio_postgres::error::Errorrocket::response::status::Custom<String>。也就是说下面的代码编译器会报错。

impl From<tokio_postgres::Error> for rocket::response::status::Custom<String> {}

报错如下:

32 | impl From<tokio_postgres::Error> for rocket::response::status::Custom<String> {}| ^^^^^---------------------------^^^^^----------------------------------------| |    |                               || |    |                               `rocket::response::status::Custom` is not defined in the current crate| |    `tokio_postgres::Error` is not defined in the current crate| impl doesn't use only types from inside the current crate

因此,我们要定义一个类型MyError作为中间类型来转换一下。
/src/models.rs

pub struct MyError {pub message: String,
}
impl From<tokio_postgres::Error> for MyError {fn from(err: Error) -> Self {Self {message: format!("{}", err),}}
}
impl From<MyError> for rocket::response::status::Custom<String> {fn from(val: MyError) -> Self {status::Custom(Status::ExpectationFailed, val.message)}
}

/src/services/note_book.rs

pub async fn insert_or_update_note(note: &Note,
) -> Result<(), rocket::response::status::Custom<String>> {let (client, connection) = connect("host=localhost dbname=notes_db user=postgres port=5432",NoTls,).await.map_err(MyError::from)?;...let _ = client.execute("insert into notes (id, title, content) values($1, $2, $3);",&[&get_system_seconds(), &note.title, &note.content],).await.map_err(MyError::from)?;Ok(())
}

src/routes/notes.rs

#[post("/api/notes", format = "application/json", data = "<note>")]
pub async fn post_notes(note: Json<Note>) -> Result<(), rocket::response::status::Custom<String>> {insert_or_update_note(&note.into_inner()).await
}

MyErrorrocket::response::status::Custom<String>之间的转换是隐式的,由编译器来完成。因此我们的错误类型的转换最终缩短为map_err(|err|MyError::from(err)),再简写为map_err(MyError::from)

关于错误处理中的类型转换应用解析就到这里。通过分析这个过程,我们可以看到,在设计模块时,我们应该确定一种错误类型,就像tokio_postgres库一样,只暴露了tokio_postgress::error::Error一种错误类型。这种设计既方便我们在设计模块时处理错误转换,也方便其我们的模块在被调用时,其它代码进行错误处理。

http://www.dt0577.cn/news/15581.html

相关文章:

  • 做项目接任务的网站网络营销案例视频
  • 东莞网站推广公司怎么自己建立网站
  • 手机端网站关键词排名天津百度搜索排名优化
  • 好用的在线客服系统抖音seo排名
  • 外国人做的关于中国的视频网站seo如何优化
  • 专门做牛肉的网站搜索引擎优化的方法
  • 网页设计基础知识总结快手seo软件下载
  • 临夏市做网站电话域名估价
  • 邢台网站建设免费做网站排名兰州网络推广优化服务
  • dw中做网站的步骤网站优化建议
  • 合肥做推拉棚网站推广网页设计与制作知识点
  • 可以做图的网站百度一下你知道
  • 做宣传单赚钱的网站中国国家培训网是真的吗
  • wordpress程序建站网站seo策划方案案例分析
  • 西安网站定制开发seo顾问服务四川
  • 做搜索引擎的网站有哪些福建seo搜索引擎优化
  • 河北省网站建设深圳推广
  • 遵义网站建设托管公司今天的最新新闻内容
  • 做网站用的什么语言如何做一个网站
  • 自己电脑做网站服务器小工具100个常用的关键词
  • 手机网站建设介绍2021年近期舆情热点话题
  • 公司做宣传网站发票可以抵扣不百度人工服务热线电话
  • wordpress中英文建站抖音推广合作方式
  • wordpress的seo优化杭州专业seo公司
  • 青岛新冠疫情最新情况泸州网站优化推广
  • 2016年做水果行业专业网站网站内部seo优化包括
  • 如何修改wordpress的字体大小北京网站优化企业
  • 有哪些网站是可以做宣传的谷歌官网登录入口
  • 设计软件培训机构排行榜抖音seo运营模式
  • 经营性网站备案时间网站推广要点