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

时间:2014-08-30 10:40:02

标签: 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();
}

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

2 个答案:

答案 0 :(得分:6)

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

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);
    }
}

答案 1 :(得分:5)

您可以将整个文件作为单个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)
}

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

缺点是你无法直接返回引用结构,因为它不能通过堆栈框架来保存单个大String。在上面的example_use中,我们必须将大String放入let才能调用words_by_line。使用不安全的代码并将String和引用包装在私有结构中是可能的,但这要复杂得多。

相关问题