在Rust中,我如何从标准输入中读取一行?

66
6个回答

87

如何在Rust中读取用户输入?中,您可以看到如何迭代所有行:

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

fn main() {
    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        println!("{}", line.unwrap());
    }
}

您还可以手动迭代而无需使用for循环:

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

fn main() {
    let stdin = io::stdin();
    let mut iterator = stdin.lock().lines();
    let line1 = iterator.next().unwrap().unwrap();
    let line2 = iterator.next().unwrap().unwrap();
}

您无法编写一行代码来实现您想要的功能。但是以下代码可以读取单行(与如何从标准输入读取单个字符串?中的答案完全相同):

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

fn main() {
    let stdin = io::stdin();
    let line1 = stdin.lock().lines().next().unwrap().unwrap();
}

您还可以使用text_io crate来进行超级简单的输入:


#[macro_use] extern crate text_io;

fn main() {
    // reads until a \n is encountered
    let line: String = read!("{}\n");
}

8
Stdin::read_line是什么? - Gerstmann
1
@Gerstmann:在我看来,那个函数使用起来相当奇怪。 - oli_obk
1
@Gerstmann 我刚试了一下:由于它是接受缓冲区而不是返回字符串,所以你不能将其与其他处理字符串的函数组合使用。 - Hi-Angel
单独的 let stdin = io::stdin(); 行不再必要。你可以直接使用 for line in io::stdin().lock().lines() { ... } - mk12

24
如果你真的想要与fgets等价的函数,那么@Gerstmann正确,你应该使用Stdin::read_line。这个方法接受一个缓冲区,你可以更好地控制将字符串放入其中:
use std::io::{self, BufRead};

fn main() {
    let mut line = String::new();
    let stdin = io::stdin();
    stdin.lock().read_line(&mut line).unwrap();
    println!("{}", line)
}

与C不同的是,你不会意外地越界缓冲区;如果输入字符串太大,它将自动调整大小。

@oli_obk - ker的答案 是你大部分时间都会看到的惯用解决方案。在这种情况下,字符串由系统管理,接口更加清晰。


13

stdin 中读取一行:

    let mut line = String::new();
    std::io::stdin().read_line(&mut line)?; // including '\n'

使用 line.trim_end() 可以去除 '\n'

读取直到 EOF:

    let mut buffer = String::new();
    std::io::stdin().read_to_string(&mut buffer)?;
使用隐式同步:
use std::io;
fn main() -> io::Result<()> {
    let mut line = String::new();
    io::stdin().read_line(&mut line)?;

    println!("You entered: {}", line);
    Ok(())
}

使用显式同步:

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

fn main() -> io::Result<()> {
    let stdin = io::stdin();
    let mut handle = stdin.lock();

    let mut line = String::new();
    handle.read_line(&mut line)?;

    println!("You entered: {}", line);
    Ok(())
}
如果您对字节数感兴趣,比如n,请使用以下代码:
let n = handle.read_line(&mut line)?;
或者
let n = io::stdin().read_line(&mut line)?; 尝试一下:
use std::io;
fn main() -> io::Result<()> {
    let mut line = String::new();
    let n = io::stdin().read_line(&mut line)?;

    println!("{} bytes read", n);
    println!("You entered: {}", line);
    Ok(())
}

请参见文档


4
从Rust 1.62开始,您可以使用Stdin::lines()函数,仅用一行代码获取一个输入行(input line)的数据。
fn main() {
    let line = std::io::stdin().lines().next().unwrap().unwrap();
}

Stdin::lines() 可以用于单行读取,但通常用于获取多行。它简化了这种用例,使得不再需要担心生命周期和锁定问题:

fn main() {
    for line in std::io::stdin().lines() {
        println!("line: {}", line.unwrap());
    }
}

1
如果你想在某个时刻离开 for 循环
use std::io::{self, BufRead};

fn main() {
    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        match line {
            Err(_) => break,    // with ^Z
            Ok(s) => println!("{}", s),
        }

    }
    println!("fin");
}

0

你可以自己编写宏。

macro_rules! read_line {
  () => {
    {
      let mut str = String::new();
      std::io::stdin().read_line(&mut str).expect("!");
      str
    }
  };
}

fn main () {
  println!("What is your name?");
  let name = read_line!();
  println!("Hello {}.", name.trim());
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接