54

我打算做一个标记器。我需要阅读用户键入的每一行,并在用户按下Ctrl+后停止阅读D

我四处搜索,只发现一个关于 Rust IO 的示例,它甚至无法编译。我查看了io模块的文档,发现该read_line()函数是ReaderUtil接口的一部分,但stdin()返回的是 a Reader

我想要的代码在 C++ 中基本上如下所示:

vector<string> readLines () {
    vector<string> allLines;
    string line;

    while (cin >> line) {
        allLines.push_back(line);
    }

    return allLines;
}

这个问题指的是 Rust 1.0 之前的部分 Rust,但一般概念在 Rust 1.0 中仍然有效。

4

8 回答 8

164

Rust 1.x(参见文档):

use std::io;
use std::io::prelude::*;

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

Rust 0.10–0.12(参见文档):

use std::io;

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

Rust 0.9(参见0.9 文档):

use std::io;
use std::io::buffered::BufferedReader;

fn main() {
    let mut reader = BufferedReader::new(io::stdin());
    for line in reader.lines() {
        print(line);
    }
}

锈 0.8:

use std::io;

fn main() {
    let lines = io::stdin().read_lines();
    for line in lines.iter() {
        println(*line);
    }
}

锈 0.7:

use std::io;

fn main() {
    let lines = io::stdin().read_lines();
    for lines.iter().advance |line| {
        println(*line);
    }
}
于 2013-07-09T11:10:54.307 回答
13

截至 2015 年 4 月 17 日,来自mdcoxFirefox Rust IRC频道。

use std::io;

fn main() {
    let mut stdin = io::stdin();
    let input = &mut String::new();

    loop {
        input.clear();
        stdin.read_line(input);
        println!("{}", input);
    }
}
于 2015-04-17T22:37:59.507 回答
4

在 Rust 1.0 及更高版本中,您可以lines在任何实现std::io::BufReadtrait 的东西上使用该方法来获取输入中行的迭代器。您也可以使用read_line,但使用迭代器更可能是您想要的。这是使用迭代器的问题中函数的一个版本;有关更详细的说明,请参见下文。(游乐场链接

use std::io;
use std::io::prelude::*;

pub fn read_lines() -> Vec<String> {
    let stdin = io::stdin();
    let stdin_lock = stdin.lock();
    let vec = stdin_lock.lines().filter_map(|l| l.ok()).collect();

    vec
}

这是一个更像问题中的 C++ 版本的版本,但在 Rust (操场)中并不是真正的惯用方式:

use std::io;
use std::io::prelude::*;

pub fn read_lines() -> Vec<String> {
    let mut vec = Vec::new();
    let mut string = String::new();

    let stdin = io::stdin();
    let mut stdin_lock = stdin.lock();

    while let Ok(len) = stdin_lock.read_line(&mut string) {
        if len > 0 {
           vec.push(string);
           string = String::new();
        } else {
            break
        }
    }

    vec
}

要获得实现的东西,BufRead需要调用lines()or read_line(),您调用std::io::stdin()以获得标准输入的句柄,然后调用lock()其结果以获得对标准输入流的独占控制(您必须具有独占控制才能获得BufRead,因为否则如果两个线程同时从标准输入读取,缓冲可能会产生任意结果)。

要将结果收集到 中Vec<String>,您可以使用collect迭代器上的方法。lines()在 上返回一个迭代器Result<String>,因此我们需要处理无法读取行的错误情况;对于这个例子,我们只是忽略了错误filter_map,只是跳过了任何错误。

类似 C++ 的版本使用read_line,它将读取的行附加到给定的字符串,然后我们将字符串推送到我们的Vec. 因为我们将字符串的所有权转移到Vec我们这样做的时候,并且因为read_line否则会继续附加到string,我们需要为每个循环分配一个新字符串(这似乎是问题中原始 C++ 版本中的一个错误,在共享相同的字符串,因此将继续累积每一行)。我们习惯于while let继续读取,直到遇到错误,如果我们读取表示输入结束的零字节,我们就会中断。

于 2018-06-20T20:20:44.473 回答
3

问题是从标准输入中读取行并返回一个向量。在 Rust 1.7 中:

fn readlines() -> Vec<String> {
    use std::io::prelude::*;
    let stdin = std::io::stdin();
    let v = stdin.lock().lines().map(|x| x.unwrap()).collect();
    v
}
于 2016-04-02T13:53:51.297 回答
3

我能想到的方法很少。

将所有输入读入单个String

let mut input = String::new();
io::stdin().read_to_end(&mut input);

将行读入Vector. panic当读取一行失败时,这个不会。相反,它会跳过失败的行。

let stdin = io::stdin();
let locked = stdin.lock();
let v: Vec<String> = locked.lines().filter_map(|line| line.ok()).collect();

此外,如果你想解析它:

将其读入字符串后执行此操作。您可以将其解析为实现FromIterator. 集合中包含的元素也必须实现FromStr。只要满足特征约束,就可以将 Vec 更改为 any Collection:FromIterator, Collection<T: FromStr>

let v: Vec<i32> = "4 -42 232".split_whitespace().filter_map(|w| w.parse().ok()).collect();

此外,您可以在以下设备上使用它StdinLock

let vv: Vec<Vec<i32>> = locked
    .lines()
    .filter_map(|l|
        l.ok().map(|s|
            s.split_whitespace().filter_map(|word| word.parse().ok()).collect()
        )
    )
    .collect();
于 2016-10-29T02:08:30.430 回答
2

呃……经过多次尝试和错误,我找到了解决方案。

我仍然希望看到更好的解决方案,所以我不会接受我自己的解决方案。

下面的代码准确地打印出用户输入的内容。

mod tokenizer {

    pub fn read () -> ~[int] {
        let reader = io::stdin();
        let mut bytes: ~[int] = ~[];

        loop {
            let byte: int = reader.read_byte();
            if byte < 0 {
                return bytes;
            }
            bytes += [byte];
        }
    }
}

fn main () {
    let bytes: ~[int] = tokenizer::read();
    for bytes.each |byte| {
        io::print(#fmt("%c", *byte as char));
    }
}

这个答案早于 Rust 1.0。请参阅现代解决方案的其他答案。

于 2012-11-27T08:12:59.577 回答
2

在 Rust 0.4 中,使用ReaderUtiltrait 来访问read_line函数。请注意,您需要将值显式转换为特征类型,例如reader as io::ReaderUtil

fn main() {
    let mut allLines = ~[];
    let reader = io::stdin();

    while !reader.eof() {
            allLines.push((reader as io::ReaderUtil).read_line());
    }

    for allLines.each |line| {
            io::println(fmt!("%s", *line));
    }
}

这个答案早于 Rust 1.0。请参阅现代解决方案的其他答案。

于 2012-11-28T09:50:49.893 回答
1

处理猜测

use std::io;

fn main() {
    println!("Guess the number!");

    println!("Please input your guess.");

    let mut guess = String::new();

    io::stdin().read_line(&mut guess).expect("Failed to read line");

    println!("You guessed: {}", guess);
}

虽然在 Rust 中有许多不同的方法可以做到这一点,但我认为这是最简单的实现方式。

use std::io;
// ...
    let mut input = String::new();
    io::stdin().read_line(&mut input).expect("Failed to read line");

    println!("Your input was `{}`", input);
// ...
于 2019-10-16T19:04:53.497 回答