Reputation: 1143
I am trying to set up a hashmap of objects / structs in rust... But I don't understand this concrete problem (a lifetime error).
#[derive(Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize, Debug)]
pub struct Node<'a> {
identifier: &'a str,
sha_id: Vec<u8>,
successor_id: Option<Vec<u8>>,
predecessor_id: Option<Vec<u8>>,
}
impl<'a> Node<'a> {
...
..
.
}
pub struct Application<'a> {
hash_map: HashMap<&'a str, Node>,
}
impl<'a> Application<'a> {
fn join(&self, node: &Node) {
self.hash_map.insert(node.identifier, node);
}
}
The error is a missing lifetime specifier in the hash_map: HashMap<&'a str, Node>
that I tried to solve changing Node to Node<'a> but It throws a "mismatched type" error when I try to insert...
I don't exactly why I have this problem missing the lifetime and I don't find solutions..
UPDATE:
#[derive(Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize, Debug)]
pub struct Node<'a> {
identifier: &'a str,
sha_id: Vec<u8>,
successor_id: Option<Vec<u8>>,
predecessor_id: Option<Vec<u8>>,
}
impl<'a> Node<'a> {
...
..
.
}
pub struct Application<'a> {
hash_map: HashMap<&'a str, Node<'a>>,
}
impl<'a> Application<'a> {
fn join(&self, node: &Node) {
self.hash_map.insert(node.identifier, *node);
}
}
And the output is:
"explicit lifetime required in the type of `node`"
UPDATE2:
pub struct Application<'a> {
hash_map: HashMap<&'a str, Node<'a>>,
}
impl<'a> Application<'a> {
fn join(&mut self, node: &'a Node<'a>) {
self.hash_map.insert(node.identifier, *node);
}
}
And the output is:
self.hash_map.insert(node.identifier, *node); cannot move out of borrowed content
COMPLETE SOLUTION
#[derive(Clone, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize, Debug)]
pub struct Node<'a> {
identifier: &'a str,
sha_id: Vec<u8>,
successor_id: Option<Vec<u8>>,
predecessor_id: Option<Vec<u8>>,
}
impl<'a> Node<'a> {
...
..
.
}
pub struct Application<'a> {
hash_map: HashMap<&'a str, Node<'a>>,
}
impl<'a> Application<'a> {
fn join(&mut self, node: Node<'a>) {
self.hash_map.insert(node.identifier, node);
}
}
Upvotes: 6
Views: 24048
Reputation: 71
For poor idiots like myself, who are trying to find out how to put hashmaps in a struct, no need to spend many hours "playing" with lifetimes(the 'a
in the above example). They are not required in the slightest, just use String instead of &str in your structure.
Edit: @neo made a slightly clearer version of my below example at rust-lang
struct ComputerConfig {
hostname: String,
// displays: Vec<DispConfig>,
}
struct MyConfig {
pub config_version: u8,
computers: HashMap<String, ComputerConfig>, // the hash map owns the struct
}
impl MyConfig {
fn new() -> MyConfig {
MyConfig {
computers: HashMap::new(),
config_version: 1,
}
}
/// Join is used to add a new ComputerConfig into the hashmap
fn join(
&mut self, // must be mutable
key: &str,
node: ComputerConfig,
) {
// do not pass a reference
self.computers.insert(key.to_string(), node); // inserting moves `node`
}
}
fn main() {
let mut cfg = MyConfig::new()
cfg.join("test", stuff);
println!("{:?}", &cfg); // outputs "12"
}
Upvotes: 4
Reputation: 44830
This simplified example seems to work:
use std::collections::HashMap;
#[derive(Clone)] // we'll be cloning it later on
struct Node<'a> {
data: &'a i32
}
struct Test<'a> {
hash_map: HashMap<&'a str, Node<'a>> // the hash map owns the struct
}
impl<'a> Test<'a> {
fn new() -> Test<'a> {
Test {hash_map: HashMap::new()}
}
fn join(
&mut self, // must be mutable
node: Node<'a>) { // do not pass a reference
self.hash_map.insert("test", node); // inserting moves `node`
}
}
fn main() {
let stuff = Node {data: &12};
let mut test = Test::new();
test.join(stuff.clone()); // if we don't clone, `stuff` will get moved
println!("{}", *test.hash_map["test"].data); // outputs "12"
}
Since std::collections::HashMap::insert
attempts to move its second argument, one can't dereference a pointer to something and pass that to this method because otherwise the pointer will become uninitialized, which isn't permitted. A way so solve this is to pass a moved value and not a pointer to join
.
Upvotes: 7