Home > other >  Add value to a HashSet in Rust and add a reference to it to another datastructure
Add value to a HashSet in Rust and add a reference to it to another datastructure

Time:11-29

I'm trying to return a Vector from a function. This happens in a loop and I need the values to exist outside of the loop. Since I perform the return multiple times and I only need the unique values, I thought I use a HashSet for this, in which I insert and then try to get a reference to the value in the next line.

I need a reference to the value in multiple other datastructures and don't want to duplicate the actual values. The values don't need to be mutable.

What I tried

use std::collections::HashSet;
fn main() {
    let mut vec: Vec<&str> = Vec::new();

    let mut books = HashSet::new();
    for i in 0..5 {
        // This could be a function call, which returns a vector of objects, which should all be
        // stored centrally and uniquely in a HashSet
        books.insert("A Dance With Dragons".to_string());

        let mut reference: &str = books.get("A Dance With Dragons").unwrap();
        // This would be done for multiple "refering" datastructures
        vec.push(reference);
    }
}

What I was expecting

Getting a pointer to the String in the HashSet for future use.

What actually happens

error[E0502]: cannot borrow `books` as mutable because it is also borrowed as immutable
  --> src/main.rs:10:9
   |
10 |         books.insert("A Dance With Dragons".to_string());
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
11 |
12 |         let mut reference: &str = books.get("A Dance With Dragons").unwrap();
   |                                   --------------------------------- immutable borrow occurs here
13 |         // This would be done for multiple "refering" datastructures
14 |         vec.push(reference);
   |         ------------------- immutable borrow later used here

For more information about this error, try `rustc --explain E0502`.
warning: `set_test` (bin "set_test") generated 2 warnings
error: could not compile `set_test` due to previous error; 2 warnings emitted

I think I'm missing a very obvious solution to this...

Thanks in advance for helping.

CodePudding user response:

You can't do this

use std::collections::HashSet;
fn main() {
    let mut v: Vec<&str> = Vec::new();

    let mut books = HashSet::new();
    for i in 0..5 {
        // this needs to borrow mutably
        books.insert("A Dance With Dragons".to_string());

        // this reference has to live as long as v
        // so on the second iteration books is still borrowed
        // which means you can't borrow it mutably any more.
        let reference: &str = books.get("A Dance With Dragons").unwrap();
        v.push(reference);
    }

    // v only goes out of scope here
}

You might find success in separating mutation and referencing like this:

fn main() {
    let mut books = HashSet::new();
    for i in 0..5 {
        books.insert("A Dance With Dragons".to_string());
    }

    let v: Vec<&str> = books.iter().collect();
}

Or by using a Rc like pigeonhgands suggests.

fn main() {
    let mut v: Vec<Rc<str>> = Vec::new();

    let mut books = HashSet::new();
    for i in 0..5 {
        books.insert(Rc::new("A Dance With Dragons".to_string()));

        // note: this clone is cheap cause it only clones the `Rc` not the whole String.
        let reference = books.get("A Dance With Dragons").unwrap().clone();
        v.push(reference);
    }
}

CodePudding user response:

The issue is that's the value in "book" could be removed and you try to save reference in a vector. It is a risk of null pointer.

You need to build book in imutable way, like this

use std::collections::HashSet;

fn main() {
    let mut vec: Vec<&str> = Vec::new();
    
    let books: HashSet<String> = vec!(
        "A Dance With Dragons".to_string(), 
        "A Dance With Dragons".to_string()).into_iter().collect();
        
    let reference: &str = books.get("A Dance With Dragons").unwrap();
     
    vec.push(reference);
}
  • Related