如何在Rust中读取用户输入?

时间:2012-11-27 07:23:23

标签: input io rust

  

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

我打算制作一个标记器。我需要读取用户键入的每一行,并在用户按下 ctrl - D 后停止阅读。

我在周围搜索并且只在Rust IO上找到one example,它甚至没有编译。我查看了io模块的文档,发现read_line()函数是ReaderUtil界面的一部分,但stdin()却返回了Reader

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

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

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

    return allLines;
}

10 个答案:

答案 0 :(得分:136)

Rust 1.x(见documentation):

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(见documentation):

use std::io;

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

Rust 0.9(见0.9 documentation):

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

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

Rust 0.8:

use std::io;

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

Rust 0.7:

use std::io;

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

答案 1 :(得分:12)

截至2015年4月17日mdcox关于mozilla 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);
    }
}

答案 2 :(得分:3)

问题是从stdin读取行并返回一个向量。在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
}

答案 3 :(得分: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更改为任何Collection:FromIteratorCollection<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();

答案 4 :(得分:2)

  

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

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

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

以下代码准确打印用户输入的内容。

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));
    }
}

答案 5 :(得分:1)

这就是我的想法(在irc.mozilla.org上#rust IRC频道的友好人士的帮助下):

use core::io::ReaderUtil;

fn read_lines() -> ~[~str] {
    let mut all_lines = ~[];

    for io::stdin().each_line |line| {
        // each_line provides us with borrowed pointers, but we want to put
        // them in our vector, so we need to *own* the lines
        all_lines.push(line.to_owned());
    }

    all_lines
}

fn main() {
    let all_lines = read_lines();

    for all_lines.eachi |i, &line| {
        io::println(fmt!("Line #%u: %s", i + 1, line));
    }
}

证明它有效:)

$ rustc readlines.rs
$ echo -en 'this\nis\na\ntest' | ./readlines
Line #1: this
Line #2: is
Line #3: a
Line #4: test

答案 6 :(得分:1)

在Rust 1.0和更高版本中,可以在实现lines特征的任何对象上使用std::io::BufRead方法,以在输入的行上获取迭代器。您也可以使用read_line,但更可能希望使用迭代器。这是使用迭代器的问题函数的版本;请参阅下面的详细说明。 (playground link

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(playground)中惯用的方式:

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()read_line()所需的东西),请调用std::io::stdin()以获取标准输入的句柄,然后调用{ {3}}的结果,以获得对标准输入流的排他控制(您必须具有排他控制权才能获得BufRead,因为否则,如果两个线程同时从stdin中读取,则缓冲可能会产生任意结果)。

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

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

答案 7 :(得分:0)

  

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

在Rust 0.4中,使用ReaderUtil特征访问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));
        }
}

答案 8 :(得分:0)

来自https://doc.rust-lang.org/book/ch02-00-guessing-game-tutorial.html#processing-a-guess

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);
}

尽管有很多不同的方法可以做到这一点,但我认为这是最简单的实现方法。

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

    println!("Your input was `{}`", input);
// ...

答案 9 :(得分:0)

有一个名为proconio的箱子。