这是从文件中读取行并将其拆分为Rust中的单词的正确方法吗?

Mic*_*zyk 4 rust

编者注:此代码示例来自1.0之前的Rust版本,并且在语法上不是有效的Rust 1.0代码.此代码的更新版本会产生不同的错误,但答案仍包含有价值的信息.

我已经实现了以下方法来返回二维数据结构中的文件中的单词:

fn read_terms() -> Vec<Vec<String>> {
    let path = Path::new("terms.txt");
    let mut file = BufferedReader::new(File::open(&path));
    return file.lines().map(|x| x.unwrap().as_slice().words().map(|x| x.to_string()).collect()).collect();
}
Run Code Online (Sandbox Code Playgroud)

这是Rust中正确的,惯用的和有效的方式吗?我想知道是否collect()需要经常调用,是否有必要调用to_string()这里来分配内存.也许返回类型应该以不同的方式定义,以便更具惯用性和效率?

小智 7

从文本文件中获取单词的方式更短,更易读.

use std::io::{BufRead, BufReader};
use std::fs::File;

let reader = BufReader::new(File::open("file.txt").expect("Cannot open file.txt"));

for line in reader.lines() {
    for word in line.unwrap().split_whitespace() {
        println!("word '{}'", word);
    }
}
Run Code Online (Sandbox Code Playgroud)


win*_*ner 6

您可以将整个文件作为单个读取String,然后构建指向内部单词的引用结构:

use std::io::{self, Read};
use std::fs::File;

fn filename_to_string(s: &str) -> io::Result<String> {
    let mut file = File::open(s)?;
    let mut s = String::new();
    file.read_to_string(&mut s)?;
    Ok(s)
}

fn words_by_line<'a>(s: &'a str) -> Vec<Vec<&'a str>> {
    s.lines().map(|line| {
        line.split_whitespace().collect()
    }).collect()
}

fn example_use() {
    let whole_file = filename_to_string("terms.txt").unwrap();
    let wbyl = words_by_line(&whole_file);
    println!("{:?}", wbyl)
}
Run Code Online (Sandbox Code Playgroud)

这将以较少的开销读取文件,因为它可以将其插入单个缓冲区,而读取行则BufReader意味着需要大量复制和分配,首先进入缓冲区内部BufReader,然后进入新分配String的每一行,然后进入String为每个单词新分配.它也将使用更少的内存,因为单个大型String和引用的向量比许多个体更紧凑String.

缺点是你不能直接返回引用的结构,因为它不能活过堆栈框架而保持单个大String.在example_use上面,我们必须将大号String放入一个let以便调用words_by_line.可以使用不安全的代码并String在私有结构中包装和引用来解决这个问题,但这要复杂得多.