Странная фраза «заимствованная стоимость живет недостаточно долго» в общих чертах

#rust #lifetime #borrow-checker

Вопрос:

Этот простой фрагмент кода сводит меня с ума:

 pub fn load_any<'a, T, K>(amp;self, key: K) -> Result<Option<T>, kv::Error> where
    T: 'a   Persistent   Debug   Serialize   for<'de> Deserialize<'de>,
    K: 'a   kv::Key<'a>,
{
    let bucket = self.store.bucket::<K,kv::Bincode<T>>(Some(T::bucket_name()))?;
    bucket
        .get(key)?.unwrap();
    Ok(None)
}

 

ошибка в том, что:

   --> src/persist.rs:47:9
   |
42 |       pub fn load_any<'a, T, K>(amp;self, key: K) -> Result<Option<T>, kv::Error> where
   |                       -- lifetime `'a` defined here
...
47 |           bucket
   |           -^^^^^
   |           |
   |  _________borrowed value does not live long enough
   | |
48 | |             .get(key)?.unwrap();
   | |_____________________- argument requires that `bucket` is borrowed for `'a`
...
51 |       }
   |       - `bucket` dropped here while still borrowed

 

Я перепробовал почти все (включая клонирование key и путаницу с жизнями), но я не могу понять, как заставить это работать.
Реальный код был другим (я, очевидно, делаю что-то со значением, возвращаемым get), но ошибка та же.
Результат Get не возвращается, и ведро используется только для вызова get() .
Компилятор Rust жалуется, что bucket он отброшен, хотя все еще заимствован, но ничто его не заимствует.

Тот же код отлично работает, заменяя универсальный K на типизированный var:

 pub fn load_str<'a, T>(amp;self, key: amp;str) -> Result<Option<T>, kv::Error> where
    T: 'a   Persistent   Debug   Serialize   for<'de> Deserialize<'de>,
{
    let bucket = self.store.bucket::<amp;str,kv::Bincode<T>>(Some(T::bucket_name()))?;
    bucket
        .get(key)?.unwrap();
    Ok(None)
   // This code works perfectly
}
 

Код использует библиотеку kv.

Комментарии:

1. Можете ли вы превратить свое решение в ответ? Таким образом, он будет соответствовать структуре вопросов и ответов этого сайта и будет легче читать/голосовать/все

2. Bucket::get принимает только Key s, привязанные к его сроку службы, но поскольку 'a производные вне функции via key всегда будут жить дольше, чем bucket определено внутри функции, компилятор пытается отклониться назад, пытаясь заставить ее работать. У меня нет решения, так как обходной путь часто заключается в for<'a> синтаксисе.

3. Точно: for<'a> это единственное решение. Проблема в самой библиотеке kv: я открыл PR (см. Мой ответ).

Ответ №1:

Я изменил код следующим образом:

 pub fn load_any<T, K>(amp;self, key: K) -> Result<Option<T>, kv::Error> where
    T: Persistent   Debug   Serialize   for<'de> Deserialize<'de>,
    K: for<'k> kv::Key<'k>,
{
    let bucket = self.store.bucket::<K,kv::Bincode<T>>(Some(T::bucket_name()))?;
    bucket
        .get(key)?.unwrap();
    Ok(None)
}

 

Я использовал выражение «на всю жизнь», используемое даже в T определении.
Я предполагаю, что это заставляет компиляцию «игнорировать» время жизни Key , которое не требуется, потому что оно не заимствовано.

Но проблема сейчас заключается в использовании метода:

 error: implementation of `kv::types::Key` is not general enough
   --> src/main.webapp.rs:146:30
    |
146 |       println!("{:?}", persist.load::<amp;str,DisyStat>("qqq"));
    |                                ^^^^ implementation of `kv::types::Key` is not general enough
    | 
   ::: /opt/rust/registry/src/github.com-1ecc6299db9ec823/kv-0.22.0/src/types.rs:7:1
    |
7   | / pub trait Key<'a>: Sized   AsRef<[u8]> {
8   | |     /// Convert from Raw
9   | |     fn from_raw_key(r: amp;'a Raw) -> Result<Self, Error>;
10  | |
...   |
14  | |     }
15  | | }
    | |_- trait `kv::types::Key` defined here
    |
    = note: `kv::types::Key<'0>` would have to be implemented for the type `amp;str`, for any lifetime `'0`...
    = note: ...but `kv::types::Key<'1>` is actually implemented for the type `amp;'1 str`, for some specific lifetime `'1`
 

Оказалось, что проблема заключается в том, что библиотека kv применяет 'a время жизни к себе для некоторых методов.

Я исправил это и открыл PR: Удалил всю жизнь из get() и содержит() методы