弃用的相应问题 https://github.com/rust-lang/rust/issues/27802#issuecomment-377537778很好地总结了问题Read::chars
并提出建议:
不关心增量处理数据的代码可以使用Read::read_to_string
反而。大概也关心的代码
想要控制其缓冲策略并与&[u8]
and
&str
尽可能大的切片,而不是一片char
在
一次。它应该基于str::from_utf8
功能以及
这valid_up_to
and error_len
的方法Utf8Error https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html类型。一个棘手的方面是处理单个char
是
用 UTF-8 表示的多个字节,这些字节恰好是
分成不同的read
调用/缓冲块。
(Utf8Error::error_len
返回None
表明这可能是
案子。)The utf-8 crate https://crates.io/crates/utf-8解决
这个,但为了灵活,提供了一个 API,可能有
标准库中包含的表面太多。
当然,以上是针对始终为 UTF-8 的数据。如果是其他
需要支持字符编码,请考虑使用encoding_rs https://crates.io/crates/encoding_rs or
encoding https://crates.io/crates/encoding crate.
你自己的迭代器
The 最有效率的解决方案I/O 调用次数是将所有内容读入一个巨大的缓冲区String
并迭代:
use std::io::{self, Read};
fn main() {
let stdin = io::stdin();
let mut s = String::new();
stdin.lock().read_to_string(&mut s).expect("Couldn't read");
for c in s.chars() {
println!(">{}<", c);
}
}
您可以将其与答案结合起来String::chars 是否有自有版本? https://stackoverflow.com/q/47193584/155423:
use std::io::{self, Read};
fn reader_chars<R: Read>(mut rdr: R) -> io::Result<impl Iterator<Item = char>> {
let mut s = String::new();
rdr.read_to_string(&mut s)?;
Ok(s.into_chars()) // from https://stackoverflow.com/q/47193584/155423
}
fn main() -> io::Result<()> {
let stdin = io::stdin();
for c in reader_chars(stdin.lock())? {
println!(">{}<", c);
}
Ok(())
}
我们现在有一个返回迭代器的函数char
s 对于任何实现的类型Read
.
一旦有了这种模式,只需决定在哪里进行内存分配与 I/O 请求的权衡即可。这是使用行大小缓冲区的类似想法:
use std::io::{BufRead, BufReader, Read};
fn reader_chars<R: Read>(rdr: R) -> impl Iterator<Item = char> {
// We use 6 bytes here to force emoji to be segmented for demo purposes
// Pick more appropriate size for your case
let reader = BufReader::with_capacity(6, rdr);
reader
.lines()
.flat_map(|l| l) // Ignoring any errors
.flat_map(|s| s.into_chars()) // from https://stackoverflow.com/q/47193584/155423
}
fn main() {
// emoji are 4 bytes each
let data = "????????????????";
let data = data.as_bytes();
for c in reader_chars(data) {
println!(">{}<", c);
}
}
最极端的情况是为每个字符执行一个 I/O 请求。这不会占用太多内存,但会产生大量 I/O 开销。
务实的答案
复制并粘贴执行Read::chars
到你自己的代码中。它将像以前一样工作。
也可以看看:
- String::chars 是否有自有版本? https://stackoverflow.com/q/47193584/155423
- 如何按字符迭代字符串 https://stackoverflow.com/q/22118221/155423