Как передать асинхронный обратный вызов c, содержащий аргумент, являющийся ссылкой? - PullRequest
1 голос
/ 10 февраля 2020

У меня есть функция, которая требует асинхронного обратного вызова (обработчик запроса); В настоящее время я пытаюсь принять вещи, которые выглядят так:

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 не работает и не добавляет новое время жизни generi c 'b. Я бы предпочел не 'static что-то, что не нуждается в этом, но я не вижу, как это сделать.

(Я также немного озадачен формулировкой сообщения - что тип параметра - не какой-то аргумент или переменная - не живет достаточно долго. Как тип не живет достаточно долго?)

Я играл с вещами немного больше, но я до сих пор не могу получить ничего, что на самом деле компилируется. Этот пример игровой площадки показывает еще одно из самых недоумений, с которыми я сталкиваюсь. Я попытался отбросить некоторые аннотации времени жизни и переместил бит for<'a> (я не уверен, в чем разница?).

1 Ответ

2 голосов
/ 10 февраля 2020

Аргумент обратного вызова, переданный как ссылка, не работает с ограничениями HRTB, когда обратный вызов помечен ключевым словом async.

Подпись с использованием async/await:

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

Is эквивалентно:

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

Это означает, что время жизни входа асинхронной функции c будет зафиксировано в будущем, возвращаемом функцией асин c.

См. параграф «Захват времени жизни». в анонимном будущем "из RF C 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!();
}

Если возможно, возможно одно решение Можно использовать объекты в штучной упаковке и избавиться от ограничений HTRB.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...