Hello!
I'm here asking for help.
I'm trying to write a generic function which uses serde_json. Here is the simplified version. To use it in rust playground I replaced serde_json references with inline functions.
// serde::Deserialize
pub trait Deserialize<'a> {}
// signature similar to serde_json::from_str
pub fn from_str<'a, T>(_s: &'a str) -> T
where
T: Deserialize<'a>
{
unimplemented!()
}
// my function
pub fn my_generic_function<'a, M>()
where M : Deserialize<'a>
{
let serialized: String = "{}".to_owned();
let _deserialized: M = from_str(serialized.as_str());
}
fn main(){}
This function takes a type parameter which implements Deserialize and tries to deserialize it from a local variable containing a string.
play: https://play.rust-lang.org/?gist=93b32919cd570faf956b82129840eb93&version=nightly&mode=debug
The error is "borrowed value does not live long enough" and I'm out of ideas.
Is it possible to modify a signature of my_generic_function to achieve something like above?
I know that this is not exactly serde_json problem, it's rather a generic Rust question, but since I encountered this issue when trying to work with serde_json, I'm asking here.
Check out the trait bounds section here: https://serde.rs/lifetimes.html. In your case the signature of my_generic_function says that type M can be deserialized from some data with lifetime 'a chosen by the caller. But the implementation attempts to deserialize M from data with lifetime chosen by my_generic_function. Depending on the caller's choice of 'a, the lifetime of serialized.as_str() may be much shorter than 'a.
As a general rule, generic parameters positioned inside of the angle brackets in fn f<...> get to be chosen by the caller.
For anyone that comes across this issue, the correct answer is to use DeserializeOwned instead of Deserialize:
https://stackoverflow.com/a/43564347
There are two main ways to write Deserialize trait bounds, whether on an impl block or a function or anywhere else.
<'de, T> where T: Deserialize<'de>
This means "T can be deserialized from some lifetime." The caller gets to decide what lifetime that is. Typically this is used when the caller also provides the data that is being deserialized from, for example in a function like serde_json::from_str. In that case the input data must also have lifetime 'de, for example it could be &'de str.
This means "T can be deserialized from any lifetime." The callee gets to decide what lifetime. Usually this is because the data that is being deserialized from is going to be thrown away before the function returns, so T must not be allowed to borrow from it. For example a function that accepts base64-encoded data as input, decodes it from base64, deserializes a value of type T, then throws away the result of base64 decoding. Another common use of this bound is functions that deserialize from an IO stream, such as serde_json::from_reader.
To say it more technically, the DeserializeOwned trait is equivalent to the higher-rank trait bound for<'de> Deserialize<'de>. The only difference is DeserializeOwned is more intuitive to read. It means T owns all the data that gets deserialized.
Most helpful comment
For anyone that comes across this issue, the correct answer is to use DeserializeOwned instead of Deserialize:
https://stackoverflow.com/a/43564347
There are two main ways to write Deserialize trait bounds, whether on an impl block or a function or anywhere else.
<'de, T> where T: Deserialize<'de>
This means "T can be deserialized from some lifetime." The caller gets to decide what lifetime that is. Typically this is used when the caller also provides the data that is being deserialized from, for example in a function like serde_json::from_str. In that case the input data must also have lifetime 'de, for example it could be &'de str.
where T: DeserializeOwned
This means "T can be deserialized from any lifetime." The callee gets to decide what lifetime. Usually this is because the data that is being deserialized from is going to be thrown away before the function returns, so T must not be allowed to borrow from it. For example a function that accepts base64-encoded data as input, decodes it from base64, deserializes a value of type T, then throws away the result of base64 decoding. Another common use of this bound is functions that deserialize from an IO stream, such as serde_json::from_reader.
To say it more technically, the DeserializeOwned trait is equivalent to the higher-rank trait bound for<'de> Deserialize<'de>. The only difference is DeserializeOwned is more intuitive to read. It means T owns all the data that gets deserialized.