Как использовать универсальный параметр rust async_trait для параметра времени жизни?

#asynchronous #rust #traits #lifetime

Вопрос:

Я пытаюсь сделать async_trait так, чтобы некоторые реализации были универсальными для типов с параметрами времени жизни:

 use async_trait::async_trait;

struct MyLifetimeType<'a> {
  s: amp;'a mut String,
}

#[async_trait]
trait MyTrait<T> {
  async fn handle(t: T);
}

struct MyImpl;

#[async_trait]
impl<'a> MyTrait<MyLifetimeType<'a>> for MyImpl {
  async fn handle(t: MyLifetimeType<'a>) {
    t.s.push_str("hi");
  }
}
 

Когда я пытаюсь скомпилировать это, я получаю

 error[E0276]: impl has stricter requirements than trait
  --> ...
   |
18 |   async fn handle(t: T);
   |   ---------------------- definition of `handle` from trait
...
25 |   async fn handle(t: MyLifetimeType<'a>) {
   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'a: 'async_trait`
 

Похоже, что проблема связана с async_trait каким-то образом использованием параметра времени жизни 'a под капотом. Когда я избавляюсь от всех async и async_trait , код компилируется нормально. Как я могу избежать этой extra requirement ошибки?

Для более подробного контекста, чтобы объяснить, почему реализуются обработчики MyTrait , которые могут работать со структурами, содержащими изменяемые указатели: у меня есть функция, которая получает RwLockReadGuard s и RwLockWriteGuard s для нескольких разных блокировок, а затем передает содержимое обработчику. Для защиты от записи мне нужен какой-то способ, чтобы обработчик изменял содержимое, поэтому я передаю изменяемый указатель.

Ответ №1:

Это известная проблема. Автор рекомендует добавлять явную привязку к сроку службы при возникновении этой ошибки:

 use async_trait::async_trait;

struct MyLifetimeType<'a> {
  s: amp;'a mut String,
}

#[async_trait]
trait MyTrait<T> {
  async fn handle(amp;self, t: T) where T: 'async_trait;
}

struct MyImpl;

#[async_trait]
impl<'a> MyTrait<MyLifetimeType<'a>> for MyImpl {

  async fn handle(amp;self, t: MyLifetimeType<'a>) {
    t.s.push_str("hi");
  }
  
}