Reading json from redis lifetime parameters

Dear all,

I have a problem with lifetimes. I cannot deal with the error messages, and sadly hard to understand whats going on.

I just simply like to create one function for reading json formatted data from redis to an object. I use tokio and serde and redis async commands.

async fn read_str_from_redis(key: &str, conn: &mut redis::aio::Connection) -> Result<String> {
    let raw: String = conn.get(key).await?;
    Ok(raw)
}

fn parse_json_str<'a, T: Deserialize<'a>>(s: &'a str) -> T {
    serde_json::from_str(s).unwrap()
}

async fn read_json<'a, T: Deserialize<'a>>(key: &str, conn: &mut redis::aio::Connection) -> Result<T> {
  let str = read_str_from_redis(key, conn).await?;
  let obj: T = parse_json_str(&str);
  Ok(obj)
}

The compiler said:

error[E0597]: `str` does not live long enough
  --> src/main.rs:64:31
   |
62 | async fn read_json<'a, T: Deserialize<'a>>(key: &str, conn: &mut redis::aio::Connection) -> Result<T> {
   |                    -- lifetime `'a` defined here
63 |   let str = read_str_from_redis(key, conn).await?;
64 |   let obj: T = parse_json_str(&str);
   |                ---------------^^^^-
   |                |              |
   |                |              borrowed value does not live long enough
   |                argument requires that `str` is borrowed for `'a`
65 |   Ok(obj)
66 | }
   | - `str` dropped here while still borrowed

But i don't get it, the lifetimes not just for function parameters? The str is created by read_json function, i don't want to live after, just pass the parser and let it go :smiley: Pls help, i'm totally lost the track.

Thanks,
Adam

You should do this instead:

async fn read_json<T: DeserializeOwned>(key: &str, conn: &mut redis::aio::Connection) -> Result<T> {
    let str = read_str_from_redis(key, conn).await?;
    let obj: T = parse_json_str(&str);
    Ok(obj)
}

In this case, the compiler is worried that T could be a type containing a reference of some kind, e.g.:

struct MyStruct<'a> {
    value: &'a str,
}

In this case, the value obj would contain a reference to str, and it would be invalid to access obj after str goes out of scope.

The DeserializeOwned trait disallows such types, so it compiles.

1 Like

Ahh, so because the compiler does not know any about what i want to do with the &str after, maybe i want to store somewhere, and after the function exit the original reference is freed. :smiley:

And this DeserializeOwned prevents this? Amazing.