Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I form a slice from a HashSet?

Tags:

rust

lifetime

A struct is defined as:

struct Node {
    set: HashSet<usize>,
    // other fields omitted
}

I have to implement a function for a trait (compatibility issues) which needs to return all elements in the set as a slice.

I am aware of something like the following function won't work:

impl Node {
    pub fn set_slice(&self) -> &[usize] {
        let elems: Vec<_> = self.set.iter().cloned().collect();
        &elems[..]
    }
}

The problem is:

error[E0597]: `elems` does not live long enough
  --> src/main.rs:11:10
   |
11 |         &elems[..]
   |          ^^^^^ borrowed value does not live long enough
12 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 9:5...
  --> src/main.rs:9:5
   |
9  | /     pub fn set_slice(&self) -> &[usize] {
10 | |         let elems: Vec<_> = self.set.iter().cloned().collect();
11 | |         &elems[..]
12 | |     }
   | |_____^

I know this requirement may sound strange. Despite why I have to do this, is there any 'good' way to achieve this?

If it is possible, I want keep the HashSet container for a O(1) lookup, and I don't want to introduce new struct members in order to save memory.

like image 843
Allen Lee Avatar asked Oct 26 '25 03:10

Allen Lee


1 Answers

No, your requirements are 100% completely impossible in safe Rust.

A HashSet / HashMap do not have a contiguous collection of data, thus there's no way to get a slice from them.


If you can change things, then you have options.

You can "render a view" of the HashSet if you can store a Vec and the method is &mut self:

struct Node {
    set: HashSet<usize>,
    view: Vec<usize>,
    // other fields omitted
}

impl Node {
    pub fn set_slice(&mut self) -> &[usize] {
        self.view.clear();
        self.view.extend(self.set.iter().cloned());
        &self.view
    }
}

You could return a Cow which would be either borrowed or owned:

use std::borrow::Cow;

impl Node {
    pub fn set_slice(&self) -> Cow<[usize]> {
        self.set.iter().cloned().collect::<Vec<_>>().into()
    }
}

You could return an iterator over the values:

impl Node {
    pub fn set_slice<'a>(&'a self) -> impl Iterator<Item = &'a usize> + 'a {
        self.set.iter()
    }
}

There's possibly a crate that uses a tightly-packed Vec as its backing storage, which could then be exposed as a slice.

like image 149
Shepmaster Avatar answered Oct 28 '25 21:10

Shepmaster



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!