0
votes

In the code below, the string does not live long enough in the Into<Body<'a>> implementation for RequestParameters<'a>. I understand why, since string comes into scope inside of into and is no longer in scope after the method finishes, but Body<'a> will keep a reference to it.

At least, that's why I think string doesn't last long enough.

What I don't understand is how to structure this code to fix string's lifetime.

The goal of this code is to make a HashMap (of "a" to "b" for example) into a string for the body of a POST request ("?a=b", for example). If there is a better way to do this, please let me know, but what I would benefit a lot from is an understanding of how to fix this lifetime issue.

If I'm wrong about why string doesn't live long enough, please let me know, as well. I'm still trying to come to grips with the lifetime system in Rust, so figuring this out will help me a ton.

struct RequestParameters<'a> {
    map: HashMap<&'a str, &'a str>,
}

impl<'a> From<HashMap<&'a str, &'a str>> for RequestParameters<'a> {
    fn from(map: HashMap<&'a str, &'a str>) -> RequestParameters<'a> {
        RequestParameters { map: map }
    }
}

impl<'a> Into<Body<'a>> for RequestParameters<'a> {
    fn into(self) -> Body<'a> {
        let string = String::from("?") +
                     &self.map
            .iter()
            .map(|entry| format!("&{}={}", entry.0, entry.1))
            .collect::<String>()[1..];
        (&string).into()
    }
}

fn main() {
    let mut parameters = HashMap::new();
    parameters.insert("a", "b");
    let client = Client::new();
    client.post("https://google.com")
        .body(RequestParameters::from(parameters));
}
1
Your question essentially boils down to returning a &str from a function, which is answered here. Please check it out, and if it does answer your question, I'll close this one as a duplicate.Vladimir Matveev

1 Answers

0
votes

As Vladimir's link points out, this is actually impossible. I changed my code to reflect this knowledge, and it now compiles.

struct RequestParameters<'a> {
    map: HashMap<&'a str, &'a str>,
}

impl<'a> From<HashMap<&'a str, &'a str>> for RequestParameters<'a> {
    fn from(map: HashMap<&'a str, &'a str>) -> RequestParameters<'a> {
        RequestParameters { map: map }
    }
}

impl<'a> RequestParameters<'a> {
    fn to_string(self) -> String {
        String::from("?") +
        &self.map.iter().map(|entry| format!("&{}={}", entry.0, entry.1)).collect::<String>()[1..]
    }
}

fn main() {
    let mut parameters = HashMap::new();
    parameters.insert("a", "b");
    let string_parameters = RequestParameters::from(parameters).to_string();
    let client = Client::new();
    client.post("https://google.com")
        .body(&string_parameters);
}

By creating the String before the Client is made I can borrow it with a longer lifetime than the Client, which fixes my issues.