Rust Rocket 如何推导出 return 包含在 Results/Options 中的类型?

How can Rust Rocket deduce return types wrapped in Results/Options?

这可能不是一个高质量的问题,因为我是 Rust 的新手。

我正在与 Rocket 合作。火箭处理程序可以 return “实现 Responder 特征的任何类型的值”。但是,我注意到我可以将实现 Responder 的东西包装在任意数量的 ResultOption 中,并且一切正常。例如:

#[post("/add_data")]
fn add_data() -> std::result::Result<Option<Response<'static>>, Status> {
    Ok(Some(Response::new()))
}

当然,Rocket 中没有代码可以处理 return 变体的所有这些不同组合,但根据我目前对 Rust 的了解,我没想到会 'just work'。有人可以解释发生了什么或它是如何工作的吗?

查看 ResponderProvided Implementations 的文档。相关的是

Option<T>

If the Option is Some, the wrapped responder is used to respond to the client. Otherwise, an Err with status 404 Not Found is returned and a warning is printed to the console.

Result<T, E> where E: Debug

If the Result is Ok, the wrapped responder is used to respond to the client. Otherwise, an Err with status 500 Internal Server Error is returned and the error is printed to the console using the Debug implementation.

Result<T, E> where E: Debug + Responder

If the Result is Ok, the wrapped Ok responder is used to respond to the client. If the Result is Err, the wrapped Err responder is used to respond to the client.

虽然不够精确,但您可以在下面看到更完整的签名:

impl<'r, R: Responder<'r>> Responder<'r> for Option<R>

impl<'r, R: Responder<'r>, E: Debug> Responder<'r> for Result<R, E>

impl<'r, R: Responder<'r>, E: Responder<'r> + Debug> Responder<'r> for Result<R, E>

所以

  1. Response<'static> 实施 Responder<'static>。因此

  2. Option<Response<'static>> 实施 Responder<'static>。因此

  3. Result<Option<Response<'static>>, Status> 实施 Responder<'static>.

查看 docs for the Responder trait at the bottom 您可以看到所有实现 Responder 特征的类型。

// If self is Some, responds with the wrapped Responder. Otherwise prints
// a warning message and returns an Err of Status::NotFound.
impl<'r, R: Responder<'r>> Responder<'r> for Option<R>

// If self is Ok, responds with the wrapped Responder. Otherwise prints
// an error message with the Err value returns an Err of Status::InternalServerError.
impl<'r, R: Responder<'r>, E: Debug> Responder<'r> for Result<R, E>

impl<'r> Responder<'r> for Response<'r>

在处理所有这些情况的宏中没有特殊的调味料,它有一个 blanket implementation of Responder 适用于 Options 和 Results包含响应者。

答案更多在于类型的工作方式。您可以在 Rust 中编写适用于任何类型的 generic type signatures

// A concrete type `A`.
struct A;

// In defining the type `Single`, the first use of `A` is not preceded by `<A>`.
// Therefore, `Single` is a concrete type, and `A` is defined as above.
struct Single(A);
//            ^ Here is `Single`s first use of the type `A`.

// Here, `<T>` precedes the first use of `T`, so `SingleGen` is a generic type.
// Because the type parameter `T` is generic, it could be anything, including
// the concrete type `A` defined at the top.
struct SingleGen<T>(T);

fn main() {
    // `Single` is concrete and explicitly takes `A`.
    let _s = Single(A);
    
    // Create a variable `_char` of type `SingleGen<char>`
    // and give it the value `SingleGen('a')`.
    // Here, `SingleGen` has a type parameter explicitly specified.
    let _char: SingleGen<char> = SingleGen('a');

    // `SingleGen` can also have a type parameter implicitly specified:
    let _t    = SingleGen(A); // Uses `A` defined at the top.
    let _i32  = SingleGen(6); // Uses `i32`.
    let _char = SingleGen('a'); // Uses `char`.
}

泛型传统上使用大写字母,如 Rocket 代码中的 R 和 E。 Rust 编译器会根据类型签名确定所使用的类型在编译时是否适用于传递的任何类型。尽管与 Rust 类型不同,Typescript 也具有非常相似的功能并且有一些 decent documentation that explains the concept. And the Responder bit is just the magic of traits.