在一组 &str 上使用 BTreeSet::range 时需要类型注释

Type annotations required when using BTreeSet::range on a set of &str

我在使用 BTreeSet::range 方法时遇到了一些问题。

use std::collections::BTreeSet;
use std::ops::Bound::Included;

fn main() {
    let set = BTreeSet::new();

    set.insert("TEST1");
    set.insert("TEST3");
    set.insert("TEST4");
    set.insert("TEST2");
    set.insert("TEST5");

    let bound = (Included("TEST3"), Included("TEST4"));
    let rg = set.range(bound);

    println!("result: {:?}", rg);
}

编译器抱怨:

error[E0283]: type annotations required: cannot resolve `_: std::cmp::Ord`
  --> src/main.rs:14:18
   |
14 |     let rg = set.range(bound);
   |                  ^^^^^

这是否意味着 &str 不能相互比较?

范围是通过..(不包括结束)或..=(包括结束)运算符构造的,例如for i in 0..3 表示 0, 1, 2。相反 for i in 0..=3 表示 0, 1, 2, 3.

要解决您的问题,您可以指定一个包含范围:

use std::collections::BTreeSet;

fn main() {
    let mut set = BTreeSet::new();

    set.insert("TEST1");
    set.insert("TEST3");
    set.insert("TEST4");
    set.insert("TEST2");
    set.insert("TEST5");

    let rg = set.range("TEST3"..="TEST4");

    println!("result: {:?}", rg);
}

这将打印

result: Range { iter: [("TEST3", ()), ("TEST4", ())] }

编译器无法从 Included 参数推断出 range 函数的第一个泛型参数 (K: Ord)。

您需要明确指定:

let rg = set.range::<&str, _>(bound);

Playground

为什么编译器无法推断出第一个泛型参数?

它确实推断出类型,但是 K 有两种候选类型:可以是 &'static strstr。 Rust 无法确定使用哪一个。

让我们分析一下range方法的定义来解释为什么Rust不能select其中之一。

pub fn range<K: ?Sized, R>(&self, range: R) -> Range<'_, T>
where
    K: Ord,
    T: Borrow<K>,
    R: RangeBounds<K>,

K 是一个动态大小的类型,T 可以表示为 KR 是一个应该实现 RangeBounds<K> 的输入。

RangeBounds<T> 有 2 种不同的元组范围实现:

// first
impl<'a, T: ?Sized + 'a> RangeBounds<T> for (Bound<&'a T>, Bound<&'a T>){}

第一个实现中,str满足T;它没有大小,并且存在 'static 生命周期。如果 Kstr,那么你可以有这样的参数:(Inbound("val1"), Inbound("val2"))

// second
impl<T> RangeBounds<T> for (Bound<T>, Bound<T>){}

实现中,&str满足T。如果 K&str 那么你可以有一个像 (Inbound("val1"), Inbound("val2"))

这样的参数

如您所见,两种类型的参数是相同的,Rust 有两个选项 K。因此,它不能 select 其中之一,因为这两个选项都适合并且它希望您明确定义它。

let rg = set.range::<str, _>(bound);

这也有效,编译器将使用第一个实现。由于两个实现做同样的事情,结果将是相同的。

另请参阅: