Reputation: 122
I want to build a parser for a generic struct by serde_json
, here is the simplifed logic. And it will generate an error: "src
does not live long enough".
But why this would cause a not-long-enough lifetime error?
Is there any way to fix it, or it is simply not recommended to write codes like this?
use serde_json;
use serde::Deserialize;
use std::marker::PhantomData;
#[derive(Default)]
struct Parser<'de, P:Deserialize<'de>>{
phantom1: PhantomData<&'de ()>,
phantom2: PhantomData<P>,
}
impl<'de, P:Deserialize<'de>> Parser<'de,P>{
fn parse(&self, src:&'de String){
serde_json::from_str::<P>(&src).unwrap();
}
}
#[derive(Default)]
struct OutterParser<'de, P:Deserialize<'de>>{
parser: Parser<'de, P>
}
impl<'de, P:Deserialize<'de>> OutterParser<'de,P>{
fn read_and_parse(&self){
let src = String::from(r#""""#);
self.parser.parse(&src);
}
}
fn main(){
let parser = OutterParser::<String>::default();
parser.read_and_parse();
}
Here is the rust playground link
Edit:
Thanks for the answer from Kevin. I once thought that 'de lifetime would be automatically derived to be a lifetime in the local parse
function. After P
struct been built from local &src
, the src
can be dropped.
Now I know the lifetime of function arguments would be less than 'de
without evident annotation.
But if the function signature is revised to fn parse(&self, &'de str)
, the 'de
will be further propagated upwards, which is not what I want.
Upvotes: 0
Views: 2545
Reputation: 122
Found answer in another question :) How to return the result of serde_json::from_str when called with a String that will be dropped at the end of the function?
An easier workaround is to use DeserializeOwned
...
use serde_json;
use serde::de::DeserializeOwned;
use std::marker::PhantomData;
#[derive(Default)]
struct Parser<P:DeserializeOwned>{
phantom2: PhantomData<P>,
}
impl<P:DeserializeOwned> Parser<P>{
fn parse(&self, src:&String){
serde_json::from_str::<P>(&src).unwrap();
}
}
#[derive(Default)]
struct OutterParser<P:DeserializeOwned>{
parser: Parser<P>
}
impl<P:DeserializeOwned> OutterParser<P>{
fn read_and_parse(&self){
let src = String::from(r#""""#);
self.parser.parse(&src);
}
}
fn main(){
let parser = OutterParser::<String>::default();
parser.read_and_parse();
}
Upvotes: 1
Reputation: 43842
P: Deserialize<'de>
means that deserializing into a value of type P
requires input data which must live for at least 'de
.
fn parse(&self, src:String){
serde_json::from_str::<P>(&src).unwrap();
Instead, you provided a reference to the local variable src
which will be dropped at the end of the parse
function, and therefore definitely lives shorter than 'de
.
In order to not have this problem, you must define parse
such that it accepts a reference that is valid for 'de
:
fn parse(&self, src: &'de str) {
Upvotes: 0