【问题标题】:Why can't a range of char be collected?为什么不能收集一定范围的字符?
【发布时间】:2019-05-27 01:42:53
【问题描述】:

我正在尝试生成一个包含小写 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。

【问题讨论】:

  • 你错过了where A: Step

标签: collections rust iterator


【解决方案1】:

编辑 2020-07-17: 从 Rust 1.45.0 开始,为 char 实现了特征 Step,使 Range&lt;char&gt;(和其他一些字符范围)作为迭代器工作.问题中的代码现在编译没有问题!

下面的旧答案。


表达式b'a'..=b'z' 的类型为RangeInclusive&lt;u8&gt; (see on Playground),因为表达式b'a' 的类型为u8:这就是字符文字前面的b 的用途。另一方面,表达式'a'..='z'(没有bs)的类型为RangeInclusive&lt;char&gt;

[...] 为RangeInclusive 提供了一个完整的Iterator 实现。

首先,这不是我们所说的“一揽子实现”(这是当 impl 块是 for Tfor &amp;T(或类似),而 T 是泛型类型时)。但是,是的,有一个 impl。但让我们仔细看看:

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

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

因此,RangeInclusive&lt;char&gt; 没有实现Iterator

所以你的解决方案已经很好了。我可能会这样写:

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

唯一真正的优势是在这个版本中,char 不会出现两次。

【讨论】:

  • @Shepmaster 很好的发现。但我认为这个问题主要是关于端点的,这个答案也顺便提到了char“问题”。对“char iterator”有一个专门的问题是更好的 IMO。
  • 谢谢!我认为chars 和u8s 之间肯定有区别,但我还不能很好地阅读Rust,所以我无法弄清楚“RangeInclusive&lt;char&gt;”的根本原因没有实现Iterator" 是char 没有实现Step。也感谢您澄清“一揽子实施”一词的用法,我以后会更加小心:) Re: 骗子,我认为 SO 在我撰写这个问题时确实向我提出了建议,但标题感觉很明显不喜欢我的问题,我什至没有点击它......
【解决方案2】:

问题在于范围类型的迭代能力取决于Step trait (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'],
);

【讨论】:

    猜你喜欢
    • 2015-07-23
    • 1970-01-01
    • 1970-01-01
    • 2021-10-11
    • 2013-11-18
    • 1970-01-01
    • 1970-01-01
    • 2017-08-04
    • 2023-03-28
    相关资源
    最近更新 更多