我有一个Warp拒绝处理程序,我这样使用它,
.recover(handle_rejection)
它是这样宣布的,
pub async fn handle_rejection(err: Rejection) -> Result<impl warp::reply::Reply, Infallible> {
如果if
语句的两边都是同一类型,则
if let Some(e) = err.find::<crate::api::error::UserError>() {
Ok(warp::reply::with_status(
warp::reply::reply(),
warp::http::StatusCode::NOT_FOUND,
))
}
else {
Ok(warp::reply::with_status(
warp::reply::reply(),
warp::http::StatusCode::NOT_FOUND,
))
}
一切都很好,但如果改变其中一方,
Ok(e.into_response())
这已经不好了,我在编译时遇到了这个错误,
error[E0308]: mismatched types
--> src/api.rs:22:8
|
22 | Ok(warp::reply::with_status(
| ____________________^
23 | | warp::reply::reply(),
24 | | warp::http::StatusCode::NOT_FOUND,
25 | | ))
| |_________________^ expected struct `Response`, found struct `WithStatus`
|
我不明白,因为那一边没有改变,这应该仍然满足impl warp::reply::Reply
,这里有什么问题?
我尝试过不同的置换,将trait对象显式地转换为as warp::reply::Reply
和&dyn warp::reply::Reply
,但它们都不起作用。
问题是impl Trait
只是一些具体的缩写实现Trait
的类型。所以这个:
fn foo() -> impl Bar {}
与此相同:
fn foo() -> SomeConcreteTypeImplementingBar {}
其中SomeConcreteTypeImplementingBar
是自动确定的(感谢@Jmb的更正(。
虽然不正确,但这样想可能会有所帮助:
fn foo<B: Bar>() -> B
这与不同,因为用户指定的类型是B
,而不是函数,但它可能有助于演示。CCD_ 9的真正目的是说";我将返回一些实现Bar
的类型,但我不会告诉您该类型是什么;。
最终,Rust必须找出要返回的具体类型。但是,请考虑以下内容:
trait Bar {}
struct One;
impl Bar for One {}
struct Two;
impl Bar for Two {}
fn foo() -> impl Bar {
if some_condition {
One
} else {
Two
}
}
编译器应该选择什么具体类型?好吧,它可能是One
或Two
,这取决于some_condition
是什么!在这种情况下,编译器不知道该选择哪种类型,因此会抛出一个错误。
这和你遇到的错误是一样的。if语句的两臂返回不同的类型,因此编译器抛出一个错误,告诉您它希望if语句两臂的类型为结构Response
或结构WithStatus
。要解决此问题,您可以:
- 创建一个实现
Reply
的新类型,该类型封装了这两种情况,然后只返回该类型 - 对函数进行返工,使其仅使用一种类型。上面的选项就是一种情况,但您也可以使用
warp
内置类型 Box
您的退货价值。生成的代码如下所示:
pub async fn handle_rejection(err: Rejection) -> Result<Box<dyn warp::reply::Reply>, Infallible> {
if let Some(e) = err.find::<crate::api::error::UserError>() {
Ok(Box::new(e.into_response()))
} else {
Ok(Box::new(warp::reply::with_status(
warp::reply::reply(),
warp::http::StatusCode::NOT_FOUND,
)))
}