【问题标题】:How do I form a slice from a HashSet?如何从 HashSet 形成切片?
【发布时间】:2018-05-08 14:34:28
【问题描述】:

结构体定义为:

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) 查找,并且我不想引入新的结构成员以节省内存。

【问题讨论】:

标签: rust lifetime


【解决方案1】:

不,您的要求在安全 Rust 中是 100% 完全不可能的。

A HashSet / HashMap 没有连续的数据集合,因此无法从中获取切片。


如果你可以改变事情,那么你就有选择。

如果您可以存储Vec 并且方法是&amp;mut self,您可以“渲染视图”HashSet

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

你可以return an iterator over the values:

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

可能a crate 使用紧密封装的Vec 作为其后备存储,然后可以作为切片公开。

【讨论】:

  • 感谢您的回答。将生命周期约束添加到临时变量 elems 是否有效?
  • @杨没有。当我说不可能时,我是认真的。如果你不能改变HashSet或者trait并且不会添加字段,那就没有办法了。
  • 我正在尝试使用Cow,一旦我拥有let cow = Cow::from(&amp;slice[..])let cow = Cow::from(vec) ,我该如何找回&amp;slice[..]。我使用了cow.borrow(),但出现了错误type annotations required: cannot resolve 'std::borrow::Cow&lt;'_, [u32]&gt;: std::borrow::Borrow&lt;_&gt;'
  • @Yang &amp;cow[..] ?
【解决方案2】:

这在简单(基本)的方式中是不可能的。

Boxmut static 可以做到这一点,但我建议修改您的 trait 并返回类似以下示例的内容:

你可以在你的 trait 中使用 AsRef&lt;[T]&gt; 而不是 &amp;[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);
}

这只是众多方法中的两种。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-27
    • 2022-01-17
    • 2012-08-27
    • 2020-11-08
    相关资源
    最近更新 更多