Rust Rocket 如何推导出包含在结果/选项中的返回类型?

问题描述

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

我正在与 Rocket 合作。 Rocket 处理程序可以返回“实现 Responder 特征的任何类型的值”。但是,我注意到我可以在任意数量ResponderResult 中包装实现 Option 的东西,并且事情似乎有效。例如:

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

当然,Rocket 中没有代码来处理所有这些不同的返回变量组合,但是根据我目前对 Rust 的了解,我没想到这会“正常工作”。有人可以解释一下发生了什么或它是如何工作的吗?

解决方法

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

Option<T>

如果Option是Some,则使用包装好的响应器来响应客户端。否则,将返回状态为 404 Not Found 的 Err,并向控制台打印警告。

Result<T,E> where E: Debug

如果 Result 为 Ok,则使用包装好的响应器来响应客户端。否则,将返回状态为 500 Internal Server Error 的 Err,并使用 Debug 实现将错误打印到控制台。

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

如果 Result 为 Ok,则使用包装好的 Ok 响应器来响应客户端。如果 Result 为 Err,则使用封装的 Err 响应器来响应客户端。

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

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,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 处的 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,E>

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

在处理所有这些情况的宏中没有特殊的调味料,而是有一个 Responderblanket implementation 适用于包含响应者的 OptionResult .

,

答案更多地取决于类型的工作方式。您可以在 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 解释了这个概念。而 Responder 位就是 magic of traits