KJansma
KJansma

Reputation: 35

How to have a function return a hash map owning a string?

use std::collections::BTreeMap;

#[derive(Debug)]
struct TestStruct {
    name: String,
    num: f64,
}

fn main() {
    let test_struct = TestStruct {name: "Test".to_string(), num: 0.42 };
    println!("{:?}", test_struct);
}


fn get_fields_as_map(test_struct: &TestStruct) ->  BTreeMap<&str, &str> {
    let mut field_map: BTreeMap<&str, &str> = BTreeMap::new();
    field_map.insert("name", &test_struct.name);
    field_map.insert("num", &test_struct.num.to_string());
    field_map
}

playground

This generates the error:

error[E0515]: cannot return value referencing temporary value
  --> src/main.rs:19:5
   |
18 |     field_map.insert("num", &test_struct.num.to_string());
   |                              --------------------------- temporary value created here
19 |     field_map
   |     ^^^^^^^^^ returns a value referencing data owned by the current function

Which I think makes sense. The to_string() function is allocating a string whose lifetime is that of the function. What I haven't figured out is how to allocate the string such that it has the same lifetime as the BTreeMap. I've tried several different ways without success and feel I'm missing something. I don't fully understand ownership.

Upvotes: 3

Views: 2587

Answers (1)

John Kugelman
John Kugelman

Reputation: 361977

You can avoid the headache if you let the map own the strings inside it rather than store references. References mean lifetimes are involved, and as you've found it's difficult to construct &strs with the required lifetimes.

Change the &str references to owned Strings and life is easy:

fn get_fields_as_map(test_struct: &TestStruct) ->  BTreeMap<String, String> {
    let mut field_map = BTreeMap::new();
    field_map.insert("name".to_owned(), test_struct.name.to_owned());
    field_map.insert("num".to_owned(), test_struct.num.to_string());
    field_map
}

Upvotes: 8

Related Questions