为什么需要 num::One 来迭代一个范围? [英] Why is num::One needed for iterating over a range?

查看:38
本文介绍了为什么需要 num::One 来迭代一个范围?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么以下带有字符范围的 for 循环无法编译?

Why does the following for loop with a char range fail to compile?

fn main() {
    for c in 'a'..'z' {
        println!("{}", c);
    }
}

错误...

main.rs:11:5: 14:2 error: the trait `core::num::One` is not implemented for the type `char` [E0277]
main.rs:11     for c in 'a'..'z' {
main.rs:12         println!("{}", c);
main.rs:13     }
main.rs:14 }
main.rs:11:5: 14:2 error: the trait `core::iter::Step` is not implemented for the type `char` [E0277]
main.rs:11     for c in 'a'..'z' {
main.rs:12         println!("{}", c);
main.rs:13     }
main.rs:14 }

为什么你甚至需要 core::num::One 来迭代一个范围?

Why do you even need core::num::One for a iterating over a range?

推荐答案

x..y 语法是 std::ops::Range { 开始:x,结束:y }.这种类型(Range)是可迭代的,因为它实现了 Iterator,特别是从那个页面:

The x..y syntax is sugar for std::ops::Range { start: x, end: y }. This type (Range<A>) is iterable due to the implementation of Iterator for it, specifically, from that page:

impl<A> Iterator for Range<A>
   where A: One + Step,
         &'a A: Add<&'a A>,
         &'a A::Output == A {
    type Item = A;

这是说如果 A 类型实现了 One<,Range 可以作为 A 上的迭代器/code> 和 Step,并且可以通过正确的方式添加.

This is saying that Range<A> can behave as an iterator over As if the type A implements One and Step, and can be added in the right way.

在这种情况下,char 不满足任何一个:char 具有 One 或可添加在语义上是无稽之谈,而且它也没有实现 Step.

In this case, char satisfies none of those: it is semantically nonsense for char to have One or be addable, and it doesn't implement Step either.

也就是说,因为 char 没有实现这些特征(因此 Range 不像迭代器那样通过 impl代码>),应该可以有手动实现:

That said, since char doesn't implement those traits (and hence Range<char> doesn't behave like an iterator via that impl), it should be possible to have a manual impl:

impl Iterator for Range<char> {
    type Item = char;

这将允许 for x in 'a'..'z' 工作.

然而,这在语义上可能不是我们想要的:.. 范围不包括最后一个元素,这对于字符来说是令人惊讶的,必须编写 'a'..'{' 来获取字母 A 到 Z.已经提出了包含范围语法的建议,例如一个例子是 'a'...'z'(更多的点 == 更多的元素),我想对于这种类型会有一个 Iterator 实现chars.

However, this probably isn't semantically what we want: the .. range doesn't include the last element, which would be suprising for characters, one would have to write 'a'..'{' to get the letters A through Z. There's been proposals for inclusive-range syntax, e.g. one example is 'a'...'z' (more dots == more elements), and I would imagine that there would be an Iterator implementation for this type with chars.

正如其他人所证明的,对于 ASCII 字符,可以使用字节文字,更一般地,可以将字符转换为 u32s:

As others have demonstrated, for ASCII characters one can use byte literals, and more generally, one can cast characters to u32s:

for i in ('à' as u32)..('æ' as u32) + 1 {
    let c = std::char::from_u32(i).unwrap();
    println!("{}", c);
}

给出:

à
á
â
ã
ä
å
æ

注意.这种方法并不完美,如果范围超过 surrogate 范围,0xD800,它会崩溃-0xDFFF.

NB. this approach isn't perfect, it will crash if the range crosses the surrogate range, 0xD800-0xDFFF.

我刚刚发布了一个 crate,char-iter,它正确地处理后者并且表现得像人们期望的那样.添加后(通过货物),它可以像这样使用:

I just published a crate, char-iter, which handles the latter correctly and behaves like one would expect. Once added (via cargo), it can be used like:

extern crate char_iter;
// ...

for c in char_iter::new('a', 'z') {
    // ...
}
for c in char_iter::new('à', 'æ') {
    // ...
}

这篇关于为什么需要 num::One 来迭代一个范围?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆