rust 使用HashSet的可变结构中的生存期

6ioyuze2  于 2023-04-30  发布在  其他
关注(0)|答案(2)|浏览(145)

我很难理解为什么rust不喜欢我的remove_str方法:

use std::cell::RefCell;
use std::collections::HashSet;

#[derive(Hash, Eq, PartialEq)]
struct StringWrap<'a>{
    s: &'a String,
}

struct Container<'a>{
    m: HashSet<StringWrap<'a>>
}

impl<'a> Container<'a>{
    fn remove_str(&mut self, s: &str){
        let string = String::from(s);
        let to_remove = StringWrap{s: &string};
        self.m.remove(&to_remove);
    }
}

它窒息了:

error[E0597]: `string` does not live long enough
  --> tests/worksheet.rs:17:39
   |
14 | impl<'a> Container<'a>{
   |      -- lifetime `'a` defined here
...
17 |         let to_remove = StringWrap{s: &string};
   |                                       ^^^^^^^ borrowed value does not live long enough
18 |         self.m.remove(&to_remove);
   |         ------------------------- argument requires that `string` is borrowed for `'a`
19 |     }
   |     - `string` dropped here while still borrowed

据我所知,我的stringto_remove的寿命足够长,允许.remove调用完成它的工作。是因为remove可能是异步的还是类似的原因?
感谢任何帮助或洞察力!

flvlnr44

flvlnr441#

据我所知,我的字符串和to_remove存活的时间足够长,可以允许。remove调用来完成其工作。是因为remove可能是异步的还是类似的原因?
不,这是因为HashSet::remove必须使用借用时项目变成的东西来调用:

pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool
where
    T: Borrow<Q>,
    Q: Hash + Eq,

但是,除非您手动为StringWrap实现Borrow,否则只能应用总括自反实现,因此只能使用&StringWrap<'a>类型的value调用remove。注意使用寿命要求。
要完成这项工作,您需要为StringWrap实现Borrow。例如,您可以执行以下操作:

impl Borrow<str> for StringWrap<'_> {
    fn borrow(&self) -> &str {
        self.s
    }
}

然后Container::remove_str只能将其参数转发给HashMap::remove

impl Container<'_> {
    fn remove_str(&mut self, s: &str) {
        self.m.remove(s);
    }
}

See it on the playground
尽管如此,在HashSet中存储引用是相当不寻常的:典型地,将所存储的Strings的所有权移动到集合中,这将使得该问题没有实际意义,因为没有使用寿命。

hvvq6cgz

hvvq6cgz2#

在HashSet::remove/take/get(arg1:(&Q):
这些内部调用将尝试从HashSet本身内部获取“T的借用版本Q”,以与T的Borrowtrait进行比较。因此,自定义impl Borrow<Q> for T具有适当的生存期是一个好主意。

相关问题