首页 > 解决方案 > rust 火箭响应工具显示由于要求冲突而导致的生命周期参数“r”

问题描述

我现在正在学习生锈。今天我面临一生的问题。我想在 rust Rocket 中实现一个 api 响应我希望 http 响应使用我的自定义实体ApiResponse 。我将构建它来替换默认的火箭响应。这是我的代码:

use rocket::serde::Deserialize;
use rocket::serde::Serialize;
use rocket::response::Responder;
use rocket::{Request, Response};
use rocket::http::{Status, ContentType};

#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
#[allow(non_snake_case)]
pub struct ApiResponse<T> {
    pub body: T,
    pub statusCode: String,
    pub resultCode: String
}

impl<'r,T> Responder<'r,'r> for ApiResponse<T> {
    fn respond_to(self, req: &Request) -> Result<Response<'r>, Status> {
        Response::build_from(self.respond_to(req).unwrap())
            .header(ContentType::JSON)
            .ok()
    }
}

impl<T> Default for ApiResponse<T> where T : Default{
    fn default() -> Self {
        ApiResponse{
            body: T::default(),
            statusCode: "200".to_string(),
            resultCode: "200".to_string()
        }
    }
}

当我编译这段代码时,显示如下错误:

$ cargo build                                                                                                                                        ‹ruby-2.7.2›
   Compiling reddwarf_music v0.1.0 (/Users/dolphin/Documents/GitHub/reddwarf_music)
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'r` due to conflicting requirements
  --> src/biz/music/../../model/response/api_response.rs:17:35
   |
17 |         Response::build_from(self.respond_to(req).unwrap())
   |                                   ^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 16:31...
  --> src/biz/music/../../model/response/api_response.rs:16:31
   |
16 |     fn respond_to(self, req: &Request) -> Result<Response<'r>, Status> {
   |                               ^^^^^^^
note: ...so that the type `rocket::Request<'_>` is not borrowed for too long
  --> src/biz/music/../../model/response/api_response.rs:17:46
   |
17 |         Response::build_from(self.respond_to(req).unwrap())
   |                                              ^^^
note: but, the lifetime must be valid for the lifetime `'r` as defined on the impl at 15:6...
  --> src/biz/music/../../model/response/api_response.rs:15:6
   |
15 | impl<'r,T> Responder<'r,'r> for ApiResponse<T> {
   |      ^^
note: ...so that the expression is assignable
  --> src/biz/music/../../model/response/api_response.rs:17:9
   |
17 | /         Response::build_from(self.respond_to(req).unwrap())
18 | |             .header(ContentType::JSON)
19 | |             .ok()
   | |_________________^
   = note: expected `Result<rocket::Response<'r>, _>`
              found `Result<rocket::Response<'_>, _>`

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'r` due to conflicting requirements
  --> src/biz/user/../../model/response/api_response.rs:17:35
   |
17 |         Response::build_from(self.respond_to(req).unwrap())
   |                                   ^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 16:31...
  --> src/biz/user/../../model/response/api_response.rs:16:31
   |
16 |     fn respond_to(self, req: &Request) -> Result<Response<'r>, Status> {
   |                               ^^^^^^^
note: ...so that the type `rocket::Request<'_>` is not borrowed for too long
  --> src/biz/user/../../model/response/api_response.rs:17:46
   |
17 |         Response::build_from(self.respond_to(req).unwrap())
   |                                              ^^^
note: but, the lifetime must be valid for the lifetime `'r` as defined on the impl at 15:6...
  --> src/biz/user/../../model/response/api_response.rs:15:6
   |
15 | impl<'r,T> Responder<'r,'r> for ApiResponse<T> {
   |      ^^
note: ...so that the expression is assignable
  --> src/biz/user/../../model/response/api_response.rs:17:9
   |
17 | /         Response::build_from(self.respond_to(req).unwrap())
18 | |             .header(ContentType::JSON)
19 | |             .ok()
   | |_________________^
   = note: expected `Result<rocket::Response<'r>, _>`
              found `Result<rocket::Response<'_>, _>`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0495`.
error: could not compile `reddwarf_music`
(base) 

我阅读了终身手册并试图理解这个问题。抱歉,我无法弄清楚我的代码哪里出错了,这似乎太复杂了。编译器告诉详细信息,但我仍然没有解决这个问题的线索。那么为什么会发生这种情况呢?我应该怎么做才能解决这个问题?我应该从这个问题中学到什么?我试图建立默认响应:

let response = Response::new();        
Response::build_from(response).header(ContentType::JSON).ok()

有用。但是当我从我自己构建时ApiResponse

 Response::build_from(self.respond_to(req).unwrap())
            .header(ContentType::JSON)
            .ok()

不工作。

标签: rust

解决方案


您在https://api.rocket.rs/master/rocket/response/trait.Responder.html有更多文档

这是特征签名

pub trait Responder<'r, 'o: 'r> {
    fn respond_to(self, request: &'r Request<'_>) -> Result<'o>;
}

和文件说

// If the response contains no borrowed data.
impl<'r> Responder<'r, 'static> for A {
    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
        todo!()
    }
}

// If the response borrows from the request.
impl<'r> Responder<'r, 'r> for B<'r> {
    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'r> {
        todo!()
    }
}

// If the response is or wraps a borrow that may outlive the request.
impl<'r, 'o: 'r> Responder<'r, 'o> for &'o C {
    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'o> {
        todo!()
    }
}

// If the response wraps an existing responder.
impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for D<R> {
    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'o> {
        todo!()
    }
}

在你的情况下,它可能是

impl<'r, T> Responder<'r,'static> for ApiResponse<T> {
    fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
        todo!()
    }
}

现在,通常 Responder 的实现在您的情况下没有意义。此实现用于发出请求,而 ApiResponse 显然旨在存储响应。

查看字符串实现

impl<'r> Responder<'r, 'static> for String {
    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
        Response::build()
            .header(ContentType::Plain)
            .sized_body(self.len(), Cursor::new(self))
            .ok()
    }
}

或 doc 命题

use std::io::Cursor;

use rocket::request::Request;
use rocket::response::{self, Response, Responder};
use rocket::http::ContentType;

struct Person {
    name: String,
    age: u16
}

impl<'r> Responder<'r, 'static> for Person {
    fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
        let string = format!("{}:{}", self.name, self.age);
        //--------------------------------^----------^-------
        Response::build_from(string.respond_to(req)?)
            .raw_header("X-Person-Name", self.name)
            .raw_header("X-Person-Age", self.age.to_string())
            .header(ContentType::new("application", "x-person"))
            .ok()
    }
}

推荐阅读