Как мне сформировать срез из HashSet? - PullRequest
0 голосов
/ 08 мая 2018

Структура определяется как:

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

Я должен реализовать функцию для признака (проблемы совместимости), который должен возвращать все элементы в наборе в виде среза.

Я знаю, что-то вроде следующей функции не будет работать:

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

Проблема:

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 | |     }
   | |_____^

Я знаю, это требование может звучать странно. Несмотря на то, почему я должен это делать, есть ли «хороший» способ добиться этого?

Если это возможно, я хочу сохранить контейнер HashSet для поиска O (1), и я не хочу вводить новые члены структуры для экономии памяти.

Ответы [ 2 ]

0 голосов
/ 08 мая 2018

Это невозможно простым (базовым) способом.

Это возможно с Box, mut static, но я рекомендую изменить вашу черту и вернуть что-то вроде следующего:

Вы можете использовать AsRef<[T]> вместо &[usize] в своей черте. Или просто верните итератор.

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);
}

Это только два пути от многих.

0 голосов
/ 08 мая 2018

Нет, ваши требования на 100% абсолютно невозможны в безопасной среде Rust.

A HashSet / HashMap не имеют непрерывного сбора данных, поэтому нет возможности получить срез из них.


Если вы можете что-то изменить, у вас есть варианты.

Вы можете «визуализировать» представление HashSet, если вы можете сохранить Vec и метод &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
    }
}

Вы можете вернуть Cow, который будет либо заимствован, либо принадлежит:

use std::borrow::Cow;

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

Вы можете вернуть итератор для значений :

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

Существует возможно ящик , который использует плотно упакованный Vec в качестве резервного хранилища, которое затем может быть выставлено в виде среза.

...