【问题标题】:Lifetime issue with Actix WebActix Web 的终身问题
【发布时间】:2019-04-27 04:18:23
【问题描述】:

我正在使用 Actix-web 实现中间件,并且遇到了我无法弄清楚的生命周期问题。

extern crate actix_web;

use actix_web::actix::{Actor, Addr, Context, System};
use actix_web::middleware::Middleware;
use actix_web::{http, server, App, HttpRequest, Responder};
use std::collections::HashMap;

pub struct CacheActor {
    caches: HashMap<String, String>,
}

impl CacheActor {
    pub fn new() -> Self {
        CacheActor {
            caches: HashMap::new(),
        }
    }
}

impl Actor for CacheActor {
    type Context = Context<Self>;
}

fn create_resource(req: HttpRequest, addr: &Addr<CacheActor>) -> impl Responder {
    unimplemented!();
    format!("Unimplemented")
}

fn list_resources(req: HttpRequest, addr: &Addr<CacheActor>) -> impl Responder {
    unimplemented!();
    format!("Unimplemented")
}

pub trait TusMiddlewareTrait {
    fn with_tus(self, addr: &Addr<CacheActor>) -> App;
}

impl TusMiddlewareTrait for App {
    fn with_tus(self, addr: &Addr<CacheActor>) -> App {
        self.route("/files", http::Method::GET, |req| list_resources(req, addr))
            .route("/files", http::Method::POST, |req| {
                create_resource(req, addr)
            })
    }
}

fn main() {
    let system = System::new("Example");
    let cache_addr = CacheActor::new().start();

    server::new(|| App::new().with_tus(&cache_addr))
        .bind("127.0.0.1:8080")
        .unwrap()
        .run();

    system.run();
}

我得到的错误如下,

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/tus/middleware.rs:84:49
   |
84 |             .route("/files", http::Method::GET, |req| list_resources(req, addr))
   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 81:5...
  --> src/tus/middleware.rs:81:5
   |
81 | /     fn with_tus(self, addr: &actix::Addr<cache::CacheActor>) -> App {
82 | |         self.middleware(TusMiddleware)
83 | |             .route("/files", http::Method::OPTIONS, tus_information)
84 | |             .route("/files", http::Method::GET, |req| list_resources(req, addr))
...  |
87 | |             })
88 | |     }
   | |_____^
   = note: ...so that the types are compatible:
           expected &&actix::address::Addr<tus::cache::CacheActor>
              found &&actix::address::Addr<tus::cache::CacheActor>
   = note: but, the lifetime must be valid for the static lifetime...

据我所知,我将cache_addr 作为对with_tus 函数的引用。在routeaddr 中的每个闭包内部也是一个引用。

我不明白为什么编译器会说the lifetime cannot outlive the anonymous lifetime #1。据我所知,cache_addr 的生命周期仍然比关闭时间长。生命周期应该覆盖到system.run() 行。有人能启发我吗?

编辑

我将上面的代码更新为 MCVE(至少可以简单地复制整个代码并运行 cargo build,同时仍然保留相同的错误消息)。我不能在 rust-playground 上运行它。目前它不支持actix crate。我尝试进一步减少它,但它给了我一个不同的错误。抱歉,我对 Rust 很陌生。

我的问题是双重的,一个是我想了解告诉我的错误是什么。其次,我想知道如何使用actix 正确执行此操作,因此示例代码依赖于actix

【问题讨论】:

    标签: rust lifetime rust-actix


    【解决方案1】:

    App::route signature

    pub fn route<T, F, R>(self, path: &str, method: Method, f: F) -> App<S> 
    where
        F: WithFactory<T, S, R>,
        R: Responder + 'static,
        T: FromRequest<S> + 'static,
    

    F 泛型依赖于 TR,它们又具有 'static 生命周期要求。

    您的闭包捕获了一个 &amp;Addr&lt;CacheActor&gt;,它在 'static 生命周期内无效,这会产生错误。

    我看到的一种可能性是直接从docs 使用App“状态”:

    应用程序状态与同一应用程序内的所有路由和资源共享。使用 http actor 时,可以使用 HttpRequest::state() 以只读方式访问状态,但可以使用 RefCell 的内部可变性来实现状态可变性。状态也可用于路由匹配谓词和中间件。

    在这种情况下应该是这样的:

    extern crate actix_web;
    
    use actix_web::actix::{Actor, Addr, Context, System};
    use actix_web::{http, server, App, HttpRequest, HttpResponse, Result};
    use std::collections::HashMap;
    use actix_web::dev::Handler;
    
    #[derive(Clone)]
    pub struct CacheActor {
        caches: HashMap<String, String>,
    }
    
    impl CacheActor {
        pub fn new() -> Self {
            CacheActor {
                caches: HashMap::new(),
            }
        }
    }
    
    impl Actor for CacheActor {
        type Context = Context<Self>;
    }
    
    impl<S> Handler<S> for CacheActor {
        type Result = String;
    
        fn handle(&self, _req: &HttpRequest<S>) -> Self::Result {
            unimplemented!();
        }
    }
    
    fn list_resources(req: &HttpRequest<Addr<CacheActor>>) -> Result<HttpResponse> {
        Ok(HttpResponse::Found()
            .header(http::header::LOCATION, format!("hello {}", req.path()))
            .finish())
    }
    
    fn main() {
        let system = System::new("Example");
    
        server::new(|| {
            let cache_addr = CacheActor::new().start();
            App::with_state(cache_addr)
                .resource("/world", |r| r.method(http::Method::GET).f(list_resources))
        })
        .bind("127.0.0.1:8080")
        .unwrap()
        .run();
    
        system.run();
    }
    

    【讨论】:

      猜你喜欢
      • 2021-06-28
      • 1970-01-01
      • 2022-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-28
      • 1970-01-01
      相关资源
      最近更新 更多