为什么 rust 的 read_line 函数使用可变引用而不是返回值?

Kin*_*407 5 rust

考虑这段代码来读取 rust 中的用户输入

use std::io;
fn main() {
    let mut input = String::new();
    io::stdin()
        .read_line(&mut input)
        .expect("error: unable to read user input");
    println!("{}", input);
}
Run Code Online (Sandbox Code Playgroud)

为什么没有办法这样做?

use std::io;
fn main() {
    let mut input = io::stdin()
        .read_line()
        .expect("error: unable to read user input");
    println!("{}", input);
}
Run Code Online (Sandbox Code Playgroud)

其他语言会更方便

use*_*342 11

原因是read_line没有针对小型交互程序进行优化;有更好的方法来实现这些。

read_line方法来自通用io::BufRead特征,其主要用途是读取可能大量的输入。这样做时,最大程度地减少执行的分配次数是有利的,这read_line就是设计用于重用现有字符串的原因。一个典型的模式是:

let mut line = String::new();
while input.read_line(&mut line)? != 0 {
    // do something with line
    ...
    line.clear();
}
Run Code Online (Sandbox Code Playgroud)

这确保(重新)分配的数量保持最少,因为line只会根据需要增加以适应输入行。一旦达到典型大小,分配将变得非常罕见,一旦读取到最大行,它们将完全消失。如果read_line()支持“方便”接口,那么上面的循环确实会更好看——例如:

while let Some(line) = read_new_line(some_input)? {
    // process the line
    ...
}
Run Code Online (Sandbox Code Playgroud)

...但需要对每一行进行新的分配和解除分配。在一次性或学习程序中,这可能完全没问题,但BufRead旨在作为高效IO的构建块,因此它的read_line方法有利于性能而不是便利。虽然在 方面实现更方便的行读取方法是微不足道的BufRead::read_line,但逆向是不可能的。

例如,这是一个分配read_line变体的实现,它允许使用如上所示(游乐场):

use std::io::{self, BufRead};

fn read_new_line(mut input: impl BufRead) -> io::Result<Option<String>> {
    let mut line = String::new();
    if input.read_line(&mut line)? == 0 {
        return Ok(None);
    }
    Ok(Some(line))
}
Run Code Online (Sandbox Code Playgroud)

请注意,对于在while循环中使用的东西read_new_line已经以 的形式存在BufRead::lines(),它在新分配的行上返回一个迭代器。尽管如此,此迭代器仍被设计为与迭代一起使用,因此在问题中显示的代码中并不方便。