Quesofat
Quesofat

Reputation: 1531

Why does a value created inside a function borrow and how can I avoid this pattern?

I'm new to rust but an engineer of over 6 years in various other languages from Javascript to Go.

I'm wondering why here the value is borrowed when I convert the response body to an "object".

I understand that the function owns the value and then the value is destroyed when the function returns BUT functions exist to create and return values. So there's clearly something fairly big I'm missing here. Can someone set me straight?

let response = match self
    .client
    .index(IndexParts::IndexId(index, id))
    .body(json!({
        "index": index,
        "body": doc,
    }))
    .send()
    .await
{
    Ok(response) => response,
    Err(err) => {
        return Err(Box::new(err));
    }
};
let response_body = match response.json::<Value>().await {
    Ok(response_body) => response_body,
    Err(err) => {
        return Err(Box::new(err));
    }
};
let response_map = response_body.as_object();
Ok(response_map)

Upvotes: 0

Views: 98

Answers (1)

user4815162342
user4815162342

Reputation: 155485

I understand that the function owns the value and then the value is destroyed when the function returns BUT functions exist to create and return values. So there's clearly something fairly big I'm missing here.

You need to return an owned value, not a reference into a local. I assume what you're doing now boils down to:

fn foo() -> &Map<String, Value> {
    let x = serde_json::json!({}); // except you get it by http
    x.as_object().unwrap() // except you do proper error handling
}

This doesn't compile because you're returning the reference to a local value. Instead, you need to return the value itself:

fn foo() -> Map<String, Value> {
    let x = serde_json::json!({}); // except you get it by http
    match x {
        Value::Object(o) => o,
        _ => unreachable!(), // you'd return Err(...)
    }
}

But even this is more complicated than you need. Since you already deserialize the value yourself, and handle the errors, you can simply ask serde to deliver a Map<String, Value> to begin with:

let response_body = match response.json::<Map<String, Value>>().await {
    Ok(response_body) => response_body,
    Err(err) => ...
};

Of course, you'll also need to adjust the return type to return the actual value instead of a reference.

Upvotes: 2

Related Questions