为什么 Rust 书中 BufRead 的有效示例是有效的?

Why is the efficient example of BufRead in the Rust book, efficient?

提问人:Joël Abrahams 提问时间:2/6/2023 更新时间:5/9/2023 访问量:414

问:

Rust 书给出了两个(与此相关)如何使用 . 他们首先给出一个“初学者友好”的例子,然后再采用更“有效的方法”。BufRead

初学者友好的示例逐行读取文件:

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

fn read_lines(filename: String) -> io::Lines<BufReader<File>> {
    // Open the file in read-only mode.
    let file = File::open(filename).unwrap(); 
    // Read the file line by line, and return an iterator of the lines of the file.
    return io::BufReader::new(file).lines(); 
}

fn main() {
    // Stores the iterator of lines of the file in lines variable.
    let lines = read_lines("./hosts".to_string());
    // Iterate over the lines of the file, and in this case print them.
    for line in lines {
        println!("{}", line.unwrap());
    }
}

“有效方法”的作用几乎相同:

use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;

fn main() {
    // File hosts must exist in current path before this produces output
    if let Ok(lines) = read_lines("./hosts") {
        // Consumes the iterator, returns an (Optional) String
        for line in lines {
            if let Ok(ip) = line {
                println!("{}", ip);
            }
        }
    }
}

// The output is wrapped in a Result to allow matching on errors
// Returns an Iterator to the Reader of the lines of the file.
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where P: AsRef<Path>, {
    let file = File::open(filename)?;
    Ok(io::BufReader::new(file).lines())
}

锈蚀书对后者说:

此过程比在内存中创建字符串更有效,尤其是处理较大的文件。

虽然后者稍微干净一些,但使用 instead instead to ,为什么返回一个更有效? 我假设一旦我们在第二个示例(in )中解开迭代器,性能方面它应该与第一个示例相同。 那为什么会有所不同呢? 为什么第二个示例中的迭代器每次都返回结果?if letunwrapResultif let Ok(lines) = read_lines("./hosts")

性能 Rust IO

评论

1赞 cafce25 2/6/2023
你是对的,“更有效的版本”几乎不是这样,也就是说,它使用而不是,所以你必须复制一次文件名的内容。这可能是因为引起复杂性问题的问题建议将整个文件读取到需要一次将整个文件读取到内存中,但是在实施时,创建 PR 的人决定坚持使用,从而保留大部分效率。StringP: AsRef<Path>StringBufReader
2赞 user4815162342 2/6/2023
书中称第二个版本为“更有效率”是很奇怪的,因为它在效率方面几乎完全相同。真正更高效的版本可能会重用相同的字符串,但会以一些使用复杂性为代价。这可以合理地称为“更简单”或“不那么通用”,但只是勉强如此。

答:

1赞 Nate Anderson 3/8/2023 #1

你是对的,“初学者友好”方法的效率同样低,并且不会“在内存中创建字符串”。似乎我们中的许多人都感到困惑。

目前至少有两个拉取请求试图解决混淆,也许你可以对你喜欢的拉取请求发表评论:

这两个拉取请求都修改了初学者友好的方法,以使用 read_to_string 而不是 .BufRead

read_to_string使初学者友好的方法“效率低下”,正如 #1641 中的文本所建议的那样。

read_to_string还给出了一个“在内存中创建字符串”的真实示例。有趣的是,“在内存中创建一个字符串”这句话从第一次提交就存在了......

...起初,这句话只描述了一种效率较低的假设方法......

...然后 #1641 以适合初学者的方法给出了一些实际代码......但它的效率同样低下!...

...在 #1679 或 #1681 之前,从未有过实际代码演示效率较低的方法!

更新 #1679 已合并到 master 中