Look for help about lifetime


#1

Hey folks, I have such a function which takes some parameters and sends a HTTP request:

    fn internal_call(&self,
                     method: Method,
                     url: &mut str,
                     payload: Option<&HashMap<&str, &str>>,
                     params: &mut HashMap<&str, &str>) {
        if !url.starts_with("http") {
            let mut prefix_url = self.prefix.clone();
            let url = prefix_url.push_str(url);
        }
        if let Some(data) = payload {
            match serde_json::to_string(&data) {
                Ok(payload_string) => {
                    params.insert("data", &payload_string);
                }
                Err(why) => {
                    panic!("couldn't convert payload to string: {} ", why);
                }
            }
        }
        let client = Client::new();

        let mut headers = Headers::new();
        headers.set(self.auth_headers());
        headers.set(ContentType::json());
        let mut response = client
            .post(&url.to_owned())
            .headers(headers)
            .form(&payload)
            .send()
            .expect("send request failed");

        let mut buf = String::new();
        response
            .read_to_string(&mut buf)
            .expect("failed to read response");
        if response.status().is_success() {
            println!("{:?}", buf);
        }
    }

Now I have encoutered an issue about lifetime:

error[E0597]: `payload_string` does not live long enough
  --> src/spotify/client.rs:50:44
   |
50 |                     params.insert("data", &payload_string);
   |                                            ^^^^^^^^^^^^^^ borrowed value does not live long enough
...
55 |             }
   |             - borrowed value only lives until here
   |
note: borrowed value must be valid for the anonymous lifetime #8 defined on the method body at 38:5...
  --> src/spotify/client.rs:38:5
   |
38 | /     fn internal_call(&self,
39 | |                      method: Method,
40 | |                      url: &mut str,
41 | |                      payload: Option<&HashMap<&str, &str>>,
...  |
76 | | 
77 | |     }
   | |_____^

The compiler complains the payload_string doesn’t live long enough, I have googled before, I know the payload_string only live inside the match statement, e.g.:

            match serde_json::to_string(&payload) {
                Ok(payload_string) => {
                    params.insert("data", &payload_string);
                }
                Err(why) => {
                    panic!("couldn't convert payload to string: {} ", why);
                }
            }

Since I want to add payload into params if it exists, then send with reqwest, but I could not handle this lifetime error, anyone help?


#2

Ok, so, first of all, the lifetime parameters in your function signature are elided, and I don’t think the default elision catches your intent here. It might be enough anyways, but maybe you’ll have to tinker at that point later.

Your problem though is that serde_json::to_string returns an owned String, and this will be dropped at the end of the function, unless you move it. Where should you move it? The obvious place would be into params, but it only takes references. Can you redesign your code so that params is a &mut HashMap<&str, String>? This seems like the most obvious way to fix it, and seems in line with the semanctics as well.