How do I form a slice from a HashSet?

余生颓废 提交于 2019-12-02 04:17:31

问题


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.


回答1:


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.




回答2:


That is impossible in simple (basic) ways.

That's possible with Box, mut static but I recommend to modify your trait and return something like in following example:

You can use AsRef<[T]> instead of &[usize] in your trait. Or simply return an iterator.

struct Node {
    set: HashSet<usize>,
}

trait SetSlice {
    type Slice: AsRef<[usize]>;
    fn get_slice_cloned(&self) -> Self::Slice;
}

impl SetSlice for Node {
    type Slice = Vec<usize>;
    fn get_slice_cloned(&self) -> Self::Slice { self.set.iter().cloned().collect() }
}

// there we use auto-impl of Iterator trait
// and return the iter.
// NOTE: we cannot use auto-impl in trait methods.
impl Node {
    fn get_neat_iter(&self) -> impl Iterator<Item = &usize> { self.set.iter() }
}

fn need_slice(slice: &[usize]) {}

fn main() {
    let n = Node { set: Default::default(), };

    // as_ref
    let all = n.get_slice_cloned();
    need_slice(all.as_ref());

    // iter-way
    let all: Vec<_> = n.get_neat_iter().cloned().collect();
    need_slice(&all);
}

This is only two ways from many.



来源:https://stackoverflow.com/questions/50236150/how-do-i-form-a-slice-from-a-hashset

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!