【问题标题】:Type annotations required when using BTreeSet::range on a set of &str在一组 &str 上使用 BTreeSet::range 时所需的类型注释
【发布时间】:2019-07-16 11:58:13
【问题描述】:

我在使用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 不能相互比较?

【问题讨论】:

    标签: rust set range binary-tree type-inference


    【解决方案1】:

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

    您需要明确指定:

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

    Playground

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

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

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

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

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

    RangeBounds&lt;T&gt; 有 2 种不同的 Tuple Range 实现:

    // 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>){}
    

    第二个实现中,&amp;str 满足T。如果K&amp;str,那么您可以使用(Inbound("val1"), Inbound("val2")) 之类的参数

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

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

    这也将起作用,编译器将使用 first 实现。由于两种实现都做同样的事情,结果将是相同的。

    另请参阅:

    【讨论】:

      【解决方案2】:

      范围是通过..(不包括端)或..=(包括端)运算符构造的,例如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", ())] }
      

      【讨论】:

      • 为什么它可以推断RangeInclusive的类型,但不能推断Bound的元组?
      • @hellow 感谢您提供替代语法。我有很多发现!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-15
      • 1970-01-01
      • 2023-03-11
      相关资源
      最近更新 更多