如何将字符串传递给HashSet的contains方法?

6

我想要使用HashSet进行快速的字符串查找,但是在不引起编译错误的情况下,我似乎找不到一种将字符串变量传递给contains方法的方式。

refs = HashSet::new();

let first_pass = link_regex.replace_all(&buffer, |caps: &Captures| {

    if caps.len() == 2 {
        refs.insert(caps.at(2).unwrap());
    }

    caps.at(1).unwrap().to_owned()
});

let out = ref_regex.replace_all(&first_pass, |caps: &Captures| {
    let capture = caps.at(1).unwrap().to_owned();

    // only remove if we've seen it before
    if refs.contains(capture) {
        return "".to_string();
    }

    capture
});

这会导致出现错误:

 src/bin/remove_links.rs:30:26: 30:33 error: mismatched types [E0308]
 src/bin/remove_links.rs:30         if refs.contains(capture) {
                                                     ^~~~~~~
 src/bin/remove_links.rs:30:26: 30:33 help: run `rustc --explain E0308` to see a detailed explanation
 src/bin/remove_links.rs:30:26: 30:33 note: expected type `&_`
 src/bin/remove_links.rs:30:26: 30:33 note:    found type `std::string::String`

如果我尝试

refs.contains(&capture)

然后我得到了
src/bin/remove_links.rs:30:17: 30:25 error: the trait bound `&str: std::borrow::Borrow<std::string::String>` is not satisfied [E0277]
src/bin/remove_links.rs:30         if refs.contains(&capture) {
                                           ^~~~~~~~

我被卡住了,我需要进行某种类型转换吗?


你能加上 // 把东西放在 refs 里 这部分吗?对于这个问题来说,它实际上是更重要的。 - Lukas Kalbertodt
1
请添加一个完整的示例,以便我们可以尝试编译。根据@LukasKalbertodt所说,这似乎是您拥有的HashSet <&str>而不是HashSet <String>,这可能是由于您如何初始化refs引起的。 - Chris Emerson
@LukasKalbertodt 我已经添加了我插入字符串的位置。所以我想在HashSet初始化时还需要做更多的事情... - ray
@ray 不,初始化没问题,但是找出一些重要的事情很重要。看看我的答案就明白我是什么意思了 :) - Lukas Kalbertodt
1个回答

16

解释

首先,让我们找出refs的类型。在HashSet::new()的时候,编译器还不知道你将会往set中添加哪些类型的元素,所以类型还不清楚。但是,编译器在这一行代码中将其确定:

refs.insert(caps.at(2).unwrap());

函数调用中的表达式(caps.at(2).unwrap())返回一个&str。因此,我们将&str放入集合中,因此refs的类型为HashSet<&str>
如果现在查看contains文档,您会发现它需要一些&Q作为参数。还有一些限制条件:where T: Borrow<Q>, Q: Hash + Eq。我们可以忽略Hash + Eq部分;它不会引起任何问题。
因此,让我们专注于T: Borrow<Q>。我们知道T是什么:&str。那么让我们看看&str有哪些Borrow的实现:文档。我们会找到许多通用的实现,其中重要的是(省略了一些噪音):
  • impl<T> Borrow<T> for T
  • impl<T> Borrow<T> for &T
因此,将我们的&str与右侧模式进行匹配,我们得出结论:Borrow<&str>Borrow<str>对于&str是实现的。因此,我们的Q可以是str,例如。这意味着contains接收到一个&str类型的参数(请记住上面的&Q)。
然而,capture的类型是String&capture是一个&String类型的表达式。每当这样的表达式用在需要毫无疑问地需要&str的位置时,编译器知道如何将&String转换为&str(解引用强制转换)。但在这种情况下,情况并不那么清楚,因为我们通过Borrow特性绕了一个弯路。因此,我们必须明确将String转换为&str。有很多方法可以实现这一点,但怎么样使用as_str()呢?因此,...
if refs.contains(capture.as_str()) {
    // ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接