在一组 &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);
为什么编译器无法推断出第一个泛型参数?
它确实推断出类型,但是 K
有两种候选类型:可以是 &'static str
或 str
。 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
可以表示为 K
而 R
是一个应该实现 RangeBounds<K>
的输入。
RangeBounds<T>
有 2 种不同的元组范围实现:
// first
impl<'a, T: ?Sized + 'a> RangeBounds<T> for (Bound<&'a T>, Bound<&'a T>){}
在第一个实现中,str
满足T
;它没有大小,并且存在 'static
生命周期。如果 K
是 str
,那么你可以有这样的参数:(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);
这也有效,编译器将使用第一个实现。由于两个实现做同样的事情,结果将是相同的。
另请参阅:
我在使用 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);
为什么编译器无法推断出第一个泛型参数?
它确实推断出类型,但是 K
有两种候选类型:可以是 &'static str
或 str
。 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
可以表示为 K
而 R
是一个应该实现 RangeBounds<K>
的输入。
RangeBounds<T>
有 2 种不同的元组范围实现:
// first
impl<'a, T: ?Sized + 'a> RangeBounds<T> for (Bound<&'a T>, Bound<&'a T>){}
在第一个实现中,str
满足T
;它没有大小,并且存在 'static
生命周期。如果 K
是 str
,那么你可以有这样的参数:(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);
这也有效,编译器将使用第一个实现。由于两个实现做同样的事情,结果将是相同的。
另请参阅: