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

时间:2016-08-25 15:39:30

标签: string rust hashset borrowing

我想使用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) {
                                           ^~~~~~~~

我很难过,我需要做某种类型的演员吗?

1 个答案:

答案 0 :(得分:8)

解释

首先,让我们找出refs的类型。在HashSet::new()点,编译器无法告诉您要将什么类型的东西放入集合中,因此类型尚不清楚。但是编译器会在这一行中找到它:

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

函数调用(caps.at(2).unwrap())内的表达式返回&str。因此我们将&str放入集合中,因此refs具有HashSet<&str>类型。

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

因此,请关注T: Borrow<Q>。我们知道T是什么:&str。因此,让我们看一下impl Borrow的{​​{1}} &str impl<T> Borrow<T> for T。我们会发现许多通用的impl,其中重要的是(删除了一些噪音):

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

因此,我们使用右手模式匹配我们的&str模式,我们得出结论:Borrow<&str>Borrow<str>Q已实现。因此,我们的str可以是contains。这意味着&str会收到&Q类型的参数(请记住上面的capture)。

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

工作解决方案

import operator
from django.db.models import Q
filter_list = [Q(name=name)]
if surname:
    filter_list.append(Q(surname=surname))

YourModel.objects.filter(reduce(operator.and_, filter_list))