2

我有一个 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,这里有什么问题?

as warp::reply::Reply我已经尝试过像和 as一样明确地转换为特征对象的不同排列,&dyn warp::reply::Reply但它们也不起作用。

4

1 回答 1

1

问题是这impl Trait只是一些具体类型的简写,它实现了Trait. 所以这:

fn foo() -> impl Bar {}

与此相同:

fn foo() -> SomeConcreteTypeImplementingBar {}

哪里SomeConcreteTypeImplementingBar是自动确定的(感谢@Jmb 的更正)。

虽然不正确,但将其视为这样可能会有所帮助:

fn foo<B: Bar>() -> B

一样,因为用户指定了类型B,而不是函数,但它可能有助于演示目的。的真正目的impl是说“我将返回一些实现的类型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
    }
}

编译器应该选择什么具体类型?好吧,它可能是OneTwo,取决于是什么some_condition!在这种情况下,编译器不知道选择哪种类型,因此会抛出错误。

这与您遇到的错误相同。if 语句的两个分支返回不同的类型,因此编译器抛出一个错误,告诉您它期望 if 语句的两个分支的类型是 structResponse或 struct 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,
    )))
}
于 2021-06-03T06:49:02.850 回答