2

我有一个需要异步回调的函数(请求处理程序);我目前正在尝试接受如下所示的内容:

async fn handle_request<'a>(request: Request, body: &'a mut (dyn AsyncRead + 'a)) -> HandlerResponse

它一直在工作,直到添加了第二个参数body,这让我很伤心。接受参数的函数如下所示:

pub async fn process_requests<H, F>(
    mut connection: Box<dyn AsyncConnection>,
    request_handler: &H,
) -> Result<(), DecodeError>
where
    for<'a> H: Fn(crate::Request, &'a mut (dyn AsyncRead + 'a)) -> F + 'a,
    F: Future<Output = HandlerResponse>,
{

通过这个函数的一部分,我们调用一个辅助函数:

handle_request(&mut connection, request_handler, request)

具有非常相似的签名;特别是,签名request_handler是相同的。它在调用request_handler. 当我尝试编译它时,我得到:

error[E0310]: the parameter type `H` may not live long enough
    |
106 | pub async fn process_requests<H, F>(
    |                               - help: consider adding an explicit lifetime bound `H: 'static`...
...
142 |                     handle_request(&mut connection, request_handler, request)
    |                     ^^^^^^^^^^^^^^
    |
note: ...so that the type `H` will meet its required lifetime bounds
    |
142 |                     handle_request(&mut connection, request_handler, request)
    |                     ^^^^^^^^^^^^^^

为什么我需要这个/我该怎么做?确实添加'static到确实似乎H:可以where消除错误,但这是正确的做法吗?实现的类型不能H带有引用,并且'static会禁止这样做吗?我不一定想那样做,但是任何试图注释一个不存在的生命的尝试 'static没有奏效H。例如,'a + Fn(...) -> F + 'a不起作用,添加新的通用'b生命周期也不起作用。我宁愿'static不要不需要它的东西,但我不知道该怎么做。

(我也对消息的措辞感到有些困惑——参数类型——而不是一些参数或变量——活得不够长。一个类型怎么活得不够长?)

我已经玩了更多的东西,但我仍然无法得到任何实际编译的东西。这个游乐场示例显示了我遇到的另一个更令人困惑的错误消息。我尝试删除一些生命周期注释,并移动了for<'a>位(我不确定有什么区别?)。

4

1 回答 1

2

async当使用关键字标记回调时,作为引用传递的回调参数不适用于 HRTB 约束。

签名使用async/await

async fn handle_request<'a>(request: Request, body: &'a mut (dyn AsyncRead + 'a)) -> HandlerResponse

相当于:

fn handle_request<'a>(request: Request, body: &'a mut (dyn AsyncRead + 'a)) -> Future<Output=HandlerResponse> + 'a

这意味着异步函数的输入生命周期将在异步函数返回的未来捕获。

请参阅RFC 2394的“匿名未来的终身捕获”段落。

将接受参数的函数声明为:

pub async fn process_requests<H, F>(
    mut connection: Box<dyn AsyncConnection>,
    request_handler: &H,
) -> Result<(), DecodeError>
where
    for<'a> H: Fn(crate::Request, &'a mut (dyn AsyncRead + 'a)) -> F + 'a,
    F: Future<Output = HandlerResponse>,
{

给出编译错误,因为 HRTB 要求:

for<'a> H: Fn(crate::Request, &'a mut (dyn AsyncRead + 'a)) -> F + 'a

“取消链接”与调用者绑定的生命周期并产生编译错误 expected bound lifetime parameter 'a, found concrete lifetime

有关 HRTB 的更多详细信息,请参见此处

要使其工作,您必须编写:

pub async fn process_requests<'a, H, F>(
    mut connection: Box<dyn AsyncConnection>,
    request_handler: &H,
) -> Result<(), DecodeError>
where
    H: Fn(crate::Request, &'a mut (dyn AsyncRead + 'a)) -> F + 'a,
    F: Future<Output = HandlerResponse>,
{

但这会给您带来另一个问题:

`body` does not live long enough

因为本地身体结构不会活得更久request_handler

async fn handle_request<'a, H, F>(
    request_handler: &H,
    request: Request,
) -> io::Result<()>
where
    H: Fn(Request, &'a mut (dyn AsyncRead + 'a)) -> F,
    F: Future<Output = String>,
{
    let mut body = Body {};
    request_handler(request, &mut body);
    unimplemented!();
}

如果可行,一种可能的解决方案是使用 Boxed 特征对象并摆脱 HTRB 约束。

于 2020-02-10T15:41:08.473 回答