将我的代码从old_io移植到新的std :: io
let path = Path::new("src/wordslist/english.txt");
let display = path.display();
let mut file = match File::open(&path) {
// The `desc` field of `IoError` is a string that describes the error
Err(why) => panic!("couldn't open {}: {}", display,
Error::description(&why)),
Ok(file) => file,
};
let mut s = String::new();
match file.read_to_string(&mut s) {
Err(why) => panic!("couldn't read {}: {}", display,
Error::description(&why)),
Ok(s) => s,
};
let words: Vec<_> = s.words().collect();
所以这可行,但要求我有一个可变的字符串来读取文件内容,然后使用单词()。collect()来收集到一个向量中,
有没有办法使用像words()这样的东西读取文件的内容而不首先将它读取到可变缓冲区字符串?我的想法是,在collect()调用可能在稍后的某个时间点发生,或者在一个单词()。map(某事物)之后,这会更有效。
答案 0 :(得分:2)
您的方法存在问题。 .words()
在&str
(字符串切片)上运行,需要父String
来引用。您的示例运行正常,因为Vec
生成的s.words().collect()
与s
位于同一范围内,因此它不会比源字符串更长。但是如果你想把它移到其他地方,你需要得到一个Vec<String>
而不是Vec<&str>
,如果你担心中间缓冲区,我假设你已经想要了。
你有一些选择。这是我能想到的两个。
您可以遍历文件的字符并在空格上分割:
// `.peekable()` gives us `.is_empty()` for an `Iterator`
// `.chars()` yields a `Result<char, CharsError>` which needs to be dealt with
let mut chars = file.chars().map(Result::unwrap).peekable();
let mut words: Vec<String> = Vec::new();
while !chars.is_empty() {
// This needs a type hint because it can't rely on info
// from the following `if` block
let word: String = chars.take_while(|ch| !ch.is_whitespace()).collect();
// We'll have an empty string if there's more than one
// whitespace character between words
// (more than one because the first is eaten
// by the last iteration of `.take_while()`)
if !word.is_empty() {
words.push(word);
}
}
您可以将File
对象包装在std::io::BufReader
中,并使用.lines()
迭代器逐行阅读:
let mut reader = BufReader::new(file);
let mut words = Vec::new();
// `.lines()` yields `Result<String, io::Error>` so we have to handle that.
// (it will not yield an EOF error, this is for abnormal errors during reading)
for line in reader.lines().map(Result::unwrap) {
words.extend(line.words().map(String::from_str));
}
// Or alternately (this may not work due to lifetime errors in `flat_map()`
let words: Vec<_> = reader.lines().map(Result::unwrap)
.flat_map(|line| line.words().map(String::from_str))
.collect();
由您来决定您喜欢哪两种解决方案。前者可能更有效但可能不太直观。后者更容易阅读,尤其是for
- 循环版本,但分配中间缓冲区。