作者:非徒雨思_184 | 来源:互联网 | 2022-12-17 07:08
既然Read::chars
迭代器已经被正式弃用了,那么在Reader
不将整个流读入内存的情况下获取来自类似stdin 的字符的迭代器的正确方法是什么?
1> Shepmaster..:
相应的弃用问题很好地总结了问题Read::chars
并提出了建议:
可以使用不关心递增处理数据的代码
Read::read_to_string
.大概需要关注的代码也希望控制其缓冲策略并使用尽可能大的切片&[u8]
和
&str
切片,而不是一次char
一个.它应该立足于str::from_utf8
功能以及对valid_up_to
与error_len
该方法
Utf8Error
的类型.一个棘手的方面是处理单个char
以UTF-8表示多个字节的情况,其中这些字节碰巧在不同的read
调用/缓冲区块中分割.(Utf8Error::error_len
返回None
表明这可能是这种情况.)的utf-8
板条箱解决了这一点,但为了是柔性的规定,可能有太多的表面的API被包括在标准库.
当然,以上是针对始终为UTF-8的数据.如果需要支持其他字符编码,请考虑使用
encoding_rs
或
encoding
包.
你自己的迭代器
在最有效的方面解决方案的数量我/ 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版本?:
use std::io::{self, Read};
fn reader_chars(mut rdr: R) -> io::Result> {
let mut s = String::new();
rdr.read_to_string(&mut s)?;
Ok(s.into_chars()) // from /sf/ask/17360801/
}
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(rdr: R) -> impl Iterator- {
// 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 /sf/ask/17360801/
}
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的自有版本?
你如何逐个字符地迭代