1

The code is pretty simple: insert a struct in a HashSet and then try use it. I understand the error I get (value borrowed after move) but I can't get a solution.

use std::collections::HashSet;

#[derive(PartialEq, Hash)]
struct MyStruct {
   s: String,
   n: i32
}

impl Eq for MyStruct {}

impl MyStruct {
   fn to_string(&self) -> String {
      format!("[s: {}, n: {}]", self.s, self.n)
   } 
}

fn main() {
   let s1 = MyStruct{ s: "aaa".to_string(), n: 50 };
   let s2 = MyStruct{ s: "bbb".to_string(), n: 100 };

   println!("s1 = {}", s1.to_string());

   let mut set: HashSet<MyStruct> = HashSet::new();
   set.insert(s1);

   // Here I get the error "Value borrowed after move"...
   // How can I use s1 or call its method to_string ?
   println!("s1 = {}", s1.to_string());
}

The compiler outputs:

  --> src\main.rs:28:24
   |
18 |    let s1 = MyStruct{ s: "aaa".to_string(), n: 50 };
   |        -- move occurs because `s1` has type `MyStruct`, which does not implement the `Copy` trait
...
24 |    set.insert(s1);
   |               -- value moved here
...
28 |    println!("s1 = {}", s1.to_string());
   |                        ^^ value borrowed here after move

Can you suggest how to store structs in HashSet and continue to use them after the insert?

Thank you

dacanalr
  • 183
  • 2
  • 14
  • 2
    Possible duplicate of [How can I keep a reference to a key after it has been inserted into a HashMap?](https://stackoverflow.com/questions/32401857/how-can-i-keep-a-reference-to-a-key-after-it-has-been-inserted-into-a-hashmap) – Boiethios Aug 01 '19 at 10:11
  • TL;DR: you cannot as is, you must use a `Rc`. – Boiethios Aug 01 '19 at 10:14

1 Answers1

1

On nightly you can enable hash_set_entry and do:

let s1 = set.get_or_insert(s1);

Which will return a &MyStruct referencing the now-moved value.

Otherwise, as mentioned, you can use an Rc, with the refcounting overhead that entails:

use std::rc::Rc;

let s1 = Rc::new(MyStruct{ s: "aaa".to_string(), n: 50 });
let mut set: HashSet<Rc<MyStruct>> = HashSet::new();
set.insert(s1.clone());
// s1 still works

Or you could make a HashSet<&MyStruct> and insert &s1 instead - of course you'd need to keep s1 alive for the duration of the HashSet.

Thomas Hurst
  • 124
  • 2
  • 4