Weird "borrowed value does not live long enough" in generics

Viewed 164

This simple piece of code is driving me nuts:

pub fn load_any<'a, T, K>(&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)
}

the error is:

  --> src/persist.rs:47:9
   |
42 |       pub fn load_any<'a, T, K>(&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

I tried almost everything (including cloning key and messing up with lifetimes) but I can't understand how to make it work. The real code was different (I obviously do something with value returned by get) but error is the same. Get result is not returned and bucket is used only to call get(). Rust compiler complains that bucket is dropped while still borrowed but nothing is borrowing it.

The same code works perfectly replacing the generic K with a typed var:

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

Code uses the kv library.

1 Answers

I modified code as follows:

pub fn load_any<T, K>(&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)
}

I used the "for any lifetime" used even in T definition. I guess this make the compile "ignore" the lifetime of Key that is not needed because it's not borrowed.

But the problem now is using the method:

error: implementation of `kv::types::Key` is not general enough
   --> src/main.webapp.rs:146:30
    |
146 |       println!("{:?}", persist.load::<&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: &'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 `&str`, for any lifetime `'0`...
    = note: ...but `kv::types::Key<'1>` is actually implemented for the type `&'1 str`, for some specific lifetime `'1`

It turned out that the problem is in the kv library enforcing 'a lifetime on self for some methods.

I fixed it and opened a PR: Removed 'a lifetime from get() and contains() methods

Related