为什么不能收集一定范围的字符?

时间:2018-12-29 17:48:30

标签: collections rust iterator

我正在尝试生成一个包含小写ASCII字符的向量。这种更复杂的方法有效:

let ascii_lowercase = (b'a'..=b'z').map(|b| b as char).collect::<Vec<char>>();

但是我首先想到的这个更简单的方法却没有:

let ascii_lowercase = ('a'..='z').collect::<Vec<char>>();

错误是:

error[E0599]: no method named `collect` found for type `std::ops::RangeInclusive<char>` in the current scope
 --> src/main.rs:2:39
  |
2 |     let ascii_lowercase = ('a'..='z').collect::<Vec<char>>();
  |                                       ^^^^^^^
  |
  = note: the method `collect` exists but the following trait bounds were not satisfied:
          `std::ops::RangeInclusive<char> : std::iter::Iterator`
          `&mut std::ops::RangeInclusive<char> : std::iter::Iterator`

这很奇怪,因为据我了解,这里有blanket implementation of Iterator for RangeInclusive

是否可以将一系列字符用作迭代器?如果是这样,为什么?如果没有,我在做什么错?我正在使用稳定的Rust 2018 1.31.1。

2 个答案:

答案 0 :(得分:7)

表达式b'a'..=b'z'的类型为RangeInclusive<u8>see on Playground),因为表达式b'a'的类型为u8b就是这样在字符文字前面是为了。另一方面,表达式'a'..='z'(无b s)的类型为RangeInclusive<char>

  

[...]为Iterator提供了RangeInclusive的全面实现。

对于一个,这不是我们所谓的“空白实现”(这是当impl块是for Tfor &T(或类似),其中T是泛型类型时) 。但是是的,有一个暗示。但是,让我们仔细看看:

impl<A> Iterator for RangeInclusive<A> 
where
    A: Step,   // <--- important

A: Step的界限很重要。如您在the documentation for Step中所见,此特征是为所有原始整数类型实现的,而不是为char实现的。这意味着对字符没有明确的“加一”操作。是的,您可以可以将其定义为下一个有效的Unicode代码点,但是Rust开发人员可能有充分的理由反对这一点。

因此, RangeInclusive<char>未实现Iterator

因此您的解决方案已经是一个不错的解决方案。我可能会这样写:

(b'a'..=b'z').map(char::from).collect::<Vec<_>>()

唯一的真正好处是,在此版本中,char不会出现两次。

答案 1 :(得分:2)

问题在于范围类型的迭代能力取决于Step特征(see extended answer)。 但是,从Rust 1.45开始,char还实现了StepPR 72413),这意味着问题中的代码现在可以正常工作!

let ascii_lowercase: Vec<char> = ('a'..='h').collect();
assert_eq!(
    ascii_lowercase,
    vec!['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'],
);