如何将字符串传递给 HashSet 包含?

How do I pass a string to HashSet contains?

我想使用 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有什么类型。在HashSet::new()点,编译器无法判断你要放入集合中的是什么类型,所以类型还不清楚。但是编译器在这一行中计算出来:

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

函数调用里面的表达式(caps.at(2).unwrap())returns一个&str。所以我们将 &strs 放入集合中,因此 refs 具有类型 HashSet<&str>

如果您现在查看 documentation for contains,您会发现它需要一些 &Q 作为参数。还有一些界限:where T: Borrow<Q>, Q: Hash + Eq。我们可以忽略 Hash + Eq 部分;它不会造成任何问题。

所以让我们关注 T: Borrow<Q>。我们确实知道 T 是什么:&str。因此,让我们看看 Borrow 中的 impl 对于 &strdocumentation。我们会发现许多通用的 impl,其中重要的是(去除了一些噪音):

  • impl<T> Borrow<T> for T
  • impl<T> Borrow<T> for &T

因此,将我们的 &str 与右手模式进行模式匹配,我们得出结论,&strBorrow<&str>Borrow<str> 已实现。例如,我们的 Q 可以是 str。这意味着 contains 接收类型为 &str 的参数(记住上面的 &Q)。

然而,

captureString 类型。 &capture 是类型 &String 的表达式。每当在毫无疑问需要 &str 的位置使用这样的表达式时,编译器就知道如何将 &String 转换为 &str(deref 强制)。然而,在这种情况下,情况并不那么清楚,因为我们绕过了 Borrow 特征。因此我们必须明确地将 String 转换为 &str。有多种方法可以实现这一点,但是 as_str() 怎么样?所以...

工作解决方案

if refs.contains(capture.as_str()) {
    // ...
}