Search code examples
genericsrustlifetimeserdeserde-json

Problem generify-ing serde_json read into a `Vec<T>` (rust)


I have several JSON files that are, at the top level, just arrays with different types of data, so it would be nice to have a function that handles this in a generic way.

This is what I have so far (rust playground link):

use std::path::Path;
use std::fs::File;
use std::io::BufReader;
use serde::Deserialize;

fn get_json<'a, T: Deserialize<'a>>(path: &Path) -> Vec<T> {
    let file = File::open(path).unwrap();
    let reader = BufReader::new(file);

    let sentences: Vec<T> = serde_json::from_reader(reader).unwrap();

    sentences
}

I don't really understand the error it gives, or how I might convince the borrow-checker that all is good:

   Compiling playground v0.0.1 (/playground)
error: lifetime may not live long enough
    --> src/lib.rs:10:29
     |
6    | fn get_json<'a, T: Deserialize<'a>>(path: &Path) -> Vec<T> {
     |             -- lifetime `'a` defined here
...
10   |     let sentences: Vec<T> = serde_json::from_reader(reader).unwrap();
     |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
     |
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
    --> /playground/.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.107/src/de.rs:2591:8
     |
2591 |     T: de::DeserializeOwned,
     |        ^^^^^^^^^^^^^^^^^^^^

error: implementation of `Deserialize` is not general enough
  --> src/lib.rs:10:29
   |
10 |     let sentences: Vec<T> = serde_json::from_reader(reader).unwrap();
   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough
   |
   = note: `Vec<T>` must implement `Deserialize<'0>`, for any lifetime `'0`...
   = note: ...but it actually implements `Deserialize<'1>`, for some specific lifetime `'1`

error: could not compile `playground` (lib) due to 2 previous errors

What can I do to fix this?


Solution

  • As the error message hints in a very opaque way, you need to change Deserialized<'a> to DeserializeOwned, and omit the lifetime. That makes your code compile and do what you want:

    fn get_json<T: DeserializeOwned>(path: &Path) -> Vec<T> {
        let file = File::open(path).unwrap();
        let reader = BufReader::new(file);
        serde_json::from_reader(reader).unwrap()
    }
    

    Playground

    The full Deserialize<'a> bound is useful when you need zero-copy deserialization, where deserialized data can point the source from which it was deserialized. In your case that is neither possible nor desired, so DeserializeOwned is exactly what you want. See the docs for more deails.