gpt4 book ai didi

lambda - 为什么我可以将对非静态局部变量的引用传递给具有“静态绑定(bind)”的函数?

转载 作者:行者123 更新时间:2023-11-29 08:14:11 26 4
gpt4 key购买 nike

我无法理解为什么可以编写如下代码

extern crate futures;
extern crate hyper;

use hyper::server::{Http, Request, Response, Service};

struct Environment {}

struct HttpService<'a> {
pub env: &'a Environment,
}

impl<'a> Service for HttpService<'a> {
type Request = Request;
type Response = Response;
type Future = futures::future::FutureResult<Self::Response, Self::Error>;
type Error = hyper::Error;

fn call(&self, _req: Request) -> Self::Future {
futures::future::ok(Response::new())
}
}

fn foo() {
let addr = "127.0.0.1:3000".parse().unwrap();
let env = Environment {};

// <<<<< why is the non-static &env accepted here?
let server = Http::new().bind(&addr, move || Ok(HttpService { env: &env }));

server.unwrap().run().unwrap();
}

bind() 方法是 defined作为

fn bind<S, Bd>(&self, addr: &SocketAddr, new_service: S) -> Result<Server<S, Bd>>
where
S: NewService<Request = Request, Response = Response<Bd>, Error = Error> + 'static,
Bd: Stream<Item = B, Error = Error>,

这意味着闭包必须具有 'static 生命周期,传递 &env 会违反此生命周期。

为什么在上面的代码中可以,而在

fn bar() {
use tokio_core::net::TcpListener;

let addr = "127.0.0.1:3000".parse().unwrap();
let env = Environment {};

let mut core = tokio_core::reactor::Core::new().unwrap();
let handle = core.handle();

use futures::Stream;
use futures::Future;

let listener = TcpListener::bind(&addr, &handle)
.unwrap()
.incoming()
.for_each(move |(socket, addr)| {
let svc = HttpService { env: &env };
let fut = Http::<hyper::Chunk>::new()
.serve_connection(socket, svc)
.map(|_| ())
.map_err(|_| panic!("err"));
handle.spawn(fut);
Ok(())
});
}

因预期的生命周期相关错误而失败:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/main.rs:50:42
|
50 | let svc = HttpService { env: &env };
| ^^^^
|
note: first, the lifetime cannot outlive the lifetime as defined on the body at 49:19...
--> src/main.rs:49:19
|
49 | .for_each(move |(socket, addr)| {
| ___________________^
50 | | let svc = HttpService { env: &env };
51 | | let fut = Http::<hyper::Chunk>::new()
52 | | .serve_connection(socket, svc)
... |
56 | | Ok(())
57 | | });
| |_________^
note: ...so that closure can access `env`
--> src/main.rs:50:42
|
50 | let svc = HttpService { env: &env };
| ^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `HttpService<'_>` will meet its required lifetime bounds
--> src/main.rs:53:18
|
53 | .map(|_| ())
| ^^^

更好的是,如何使用更强大的 Http::serve_*() 函数来编写后一部分?

我正在使用

  • 使用rust 1.22.1
  • super 0.11.15
  • 东京核心 0.1.12

最佳答案

通过使用 move 关键字,您已将 Environment 变量的所有权转移给闭包。这意味着闭包本身没有引用,因此不涉及生命周期。闭包的返回值的生命周期与闭包本身相关联,但这是允许的。

请注意,本例使用 NewService

在 Tokio 示例中,您调用 Handle::spawn ,这需要一个 'static 生命周期。 Future 引用了不满足该要求的 Environment

请注意,本例使用 Service

关于lambda - 为什么我可以将对非静态局部变量的引用传递给具有“静态绑定(bind)”的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48486343/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com