Search code examples
rustserde

I can not deserialize json String to struct with serde


I have trouble deserializing json to struct.

Here is code that simulates my problem:

use std::sync::mpsc;
use std::sync::mpsc::{Receiver, Sender };

extern crate serde_json;
extern crate serde;
#[macro_use]
extern crate serde_derive;

#[derive(Deserialize, Debug)]
struct Foo<'a> {
    a: u32,
    b: u32,
    c: &'a str,
}

fn main() {

    let (msg_tx, msg_rx): (Sender<Foo>, Receiver<Foo>) = mpsc::channel();
    {
        let js = r#"{"a":33, "b":44, "c": "ss"}"#; // initially I have a json String, here I simulate a problem
        let js_string = String::from(js);
        let f = test(js_string.as_str());

        msg_tx.send(f);
    }
}

fn test(js: &str) -> Foo {
    let foo: Foo = serde_json::from_str(js).unwrap();

    foo
}

Running that code results to the error 'js' does not live long enough. I know that changing the type of Foo c field to String will resolve the problem, but I would like to know if there is a another solution. The reason for this error is the way serde crate works in that situation, - it uses inside returned foo variable a reference to original variable, which is js_string, so it goes out of scope just after calling msg_tx.send(f); but f has a reference to it and lives longer than that scope. I'm still a rust beginner and want to master lifetime concept. I tried to fix my problem with function wrapper to set right lifetime, but failed.


Solution

  • You have to ensure that js_string lives longer than the channel, to ensure this you can create a scope for "working" with the channel:

    use std::sync::mpsc;
    use std::sync::mpsc::{Receiver, Sender };
    
    extern crate serde_json;
    extern crate serde;
    #[macro_use]
    extern crate serde_derive;
    
    #[derive(Deserialize, Debug)]
    struct Foo<'a> {
        a: u32,
        b: u32,
        c: &'a str,
    }
    
    fn main() {
    
        let js = r#"{"a":33, "b":44, "c": "ss"}"#;
        let js_string = String::from(js);
        let f = test(js_string.as_str());
        {
            let (msg_tx, msg_rx): (Sender<Foo>, Receiver<Foo>) = mpsc::channel();
            msg_tx.send(f);
            
        } // channel is dropped here and js_string is no longer borrowed
    
    
    } // js_string is dropped here
    
    fn test(js: &str) -> Foo {
        let foo: Foo = serde_json::from_str(js).unwrap();
        foo
    }