编者注:这个问题是指在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;
}
答案 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: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();
答案 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的箱子。