String 使用新的std::fs::文件创建字符串向量

String 使用新的std::fs::文件创建字符串向量,string,performance,vector,rust,String,Performance,Vector,Rust,将我的代码从旧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!("co

将我的代码从旧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();
let path=path::new(“src/wordslist/english.txt”);
let display=path.display();
让mut file=match file::open(&path){
//'IoError'的'desc'字段是一个描述错误的字符串
Err(why)=>panic!(“无法打开{}:{}”,显示,
错误::说明(&原因)),
确定(文件)=>文件,
};
让mut s=String::new();
匹配文件。读取到字符串(&mut s){
Err(why)=>panic!(“无法读取{}:{}”,显示,
错误::说明(&原因)),
Ok(s)=>s,
};
让单词:Vec=s.words().collect();
这是可行的,但需要一个可变字符串s来读取文件内容,然后使用words().collect()将其聚集到一个向量中


有没有一种方法可以使用words()之类的东西将文件内容读入向量,而不首先将其读入可变缓冲区字符串?我的想法是,如果collect()调用可能在稍后发生,或者在words().map(某物)之后发生,那么这将更有效

您的方法有问题
.words()
在一个
&str
(字符串片段)上操作,该字符串需要一个父
字符串
来引用。您的示例运行良好,因为由
s.words().collect()
生成的
Vec
s
位于同一范围内,因此它不会超过源字符串。但是如果你想把它移到别的地方,你需要一个
Vec
,而不是
Vec
,如果你关心中间缓冲区的话,我假设你已经想要了

你确实有一些选择。这里有两个我能想到的

您可以迭代文件中的字符,并在空白处拆分:

// `.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);
    }
}

这取决于你决定你喜欢哪两种解决方案。前者可能更有效,但可能不那么直观。后者更容易阅读,尤其是循环版本的
,但分配了中间缓冲区。

旧的io方式允许我将文件读取到字符串而不可变:让word\u backing:string=match file.read\u to\u string(){Err(why)=>panic!(“无法读取{}:{}”,display,why.desc),Ok(string)=>字符串,};让words:Vec=word_backing.words().collect();使用新的std::IOT没有办法做到这一点吗?
旧io中的
读取到字符串()
与新io中的
读取到字符串()
之间的唯一区别是,您需要自己分配字符串,并将其作为
&mut string
传递。这为中间状态提供了更好的表示方式,因为该方法可以返回错误,但您仍然可以使用到该点为止读取的内容,而不是丢失所有内容。@AustinB如果您碰巧已经分配了一个字符串或希望从多个源读取到一个字符串,它还允许您避免额外的分配。
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();