How do I print output without a trailing newline in Rust? - rust

The macro println! in Rust always leaves a newline character at the end of each output. For example
println!("Enter the number : ");
io::stdin().read_line(&mut num);
gives the output
Enter the number :
56
I don't want the user's input 56 to be on a new line. How do I do this?

It's trickier than it would seem at first glance. Other answers mention the print! macro but it's not quite that simple. You'll likely need to flush stdout, as it may not be written to the screen immediately. flush() is a trait method that is part of std::io::Write so that needs to be in scope for it to work (this is a pretty easy early mistake).
use std::io;
use std::io::Write; // <--- bring flush() into scope
fn main() {
println!("I'm picking a number between 1 and 100...");
print!("Enter a number: ");
io::stdout().flush().unwrap();
let mut val = String::new();
io::stdin().read_line(&mut val)
.expect("Error getting guess");
println!("You entered {}", val);
}

You can use the print! macro instead.
print!("Enter the number : ");
io::stdin().read_line(&mut num);
Beware:
Note that stdout is frequently line-buffered by default so it may be necessary to use io::stdout().flush() to ensure the output is emitted immediately.

Don't use the print/ln!-macros. Use write/ln!-macros.
It is more verbose, but print/ln! are problematic for using in command-line apps where their output might get piped or redirected to other apps, which is characteristic for Unix environments.
There is used always the same (only once requested and "buffered") stdout-device, but the stdout-device of the system is changed for piping/redirecting. So for each output to stdout you have to request the current stdout-device (std::io::stdout()). This can be done with write/ln!-macros.
So to say print/ln! is broken and there is an open issue since years.

Related

The print! macro does not output information to the console in a timely manner when there is a thread::sleep [duplicate]

I am studying Rust and upon working on the Guessing Game I found this odd behaviour:
use std::io;
fn main() {
println!("Welcome!");
let mut input = String::new();
print!("Please type something:"); // this line is not printed UNTIL the Enter key is pressed
io::stdin()
.read_line(&mut input)
.expect("Failed to read input!");
println!("Bye!");
}
The following happens:
Welcome! is printed
Please type something: is NOT printed
If you type some text and press Enter, you will see your text followed by Please type something:Bye!
How can I print a message to the standard output and have the input being printed on the same line?
For instance:
Please enter your name:
(user types Chuck Norris)
Please enter your name: Chuck Norris
From the docs for std::print:
Note that stdout is frequently line-buffered by default so it may be necessary to use io::stdout().flush() to ensure the output is emitted immediately.
So looks like you need to call io::stdout().flush().

The print!() macro is not working in a loop {} block with other code in Rust [duplicate]

I am studying Rust and upon working on the Guessing Game I found this odd behaviour:
use std::io;
fn main() {
println!("Welcome!");
let mut input = String::new();
print!("Please type something:"); // this line is not printed UNTIL the Enter key is pressed
io::stdin()
.read_line(&mut input)
.expect("Failed to read input!");
println!("Bye!");
}
The following happens:
Welcome! is printed
Please type something: is NOT printed
If you type some text and press Enter, you will see your text followed by Please type something:Bye!
How can I print a message to the standard output and have the input being printed on the same line?
For instance:
Please enter your name:
(user types Chuck Norris)
Please enter your name: Chuck Norris
From the docs for std::print:
Note that stdout is frequently line-buffered by default so it may be necessary to use io::stdout().flush() to ensure the output is emitted immediately.
So looks like you need to call io::stdout().flush().

Why does rust's read_line function use a mutable reference instead of a return value?

Consider this code to read the user input in 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);
}
why is there no way to do it like this?
use std::io;
fn main() {
let mut input = io::stdin()
.read_line()
.expect("error: unable to read user input");
println!("{}", input);
}
it would be more convenient to other languages
TL;DR The closest you have is lines(), and the reason read_line works like it does is efficiency. The version that uses lines() looks like this:
use std::io::{self, BufRead};
fn main() {
// get next line from stdin and print it
let input = io::stdin().lock().lines().next().unwrap().expect("IO error");
println!("{}", input);
}
In general, read_line() is not designed for use in small interactive programs; there are better ways to implement those.
The read_line method comes from the generic io::BufRead trait, and its primary use is reading input, typically redirected from files or other programs, and possibly coming in large quantities. When processing large amounts of data, it is advantageous to minimize the number of allocations performed, which is why read_line is designed to reuse an existing string. A typical pattern would be:
let mut line = String::new();
while input.read_line(&mut line)? != 0 {
// do something with line
...
line.clear();
}
The number of (re-)allocations is kept minimal, as line will grow only as needed to accommodate the input lines. Once a typical size is reached, allocations will become very rare, and once the largest line is read, they will disappear altogether. If read_line() supported the "convenient" interface, then the above loop would indeed look nicer - for example:
while let Some(line) = read_new_line(some_input)? {
// process the line
...
}
...but would require a new allocation and deallocation for each line. In throw-away or learning programs this can be perfectly fine, but BufRead is intended as a building block for efficient IO, so its read_line method favors performance over convenience.

How to split a String in Rust that I take as an input with read!()

I want to split a String that I give as an input according to white spaces in it.
I have used the split_whitespaces() function but when I use this function on a custom input it just gives me the first String slice.
let s:String = read!();
let mut i:usize = 0;
for token in s.split_whitespace() {
println!("token {} {}", i, token);
i+=1;
}
What am I missing?
As far as I know, read! is not a standard macro. A quick search reveals that is probably is from the text_io crate (if you are using external crates you should tell so in the question).
From the docs in that crate:
The read!() macro will always read until the next ascii whitespace character (\n, \r, \t or space).
So what you are seeing is by design.
If you want to read a whole line from stdin you may try the standard function std::Stdin::read_line.
You are missing test cases which could locate the source of the problem. Split the code into a function and replace the read!()-macro with a test case, which you could put in main for now, where you provide different strings to the function and observe the output.
fn strspilit(s:String){
let mut i:usize = 0;
for token in s.split_whitespace() {
println!("token {} {}", i, token);
i+=1;
}
}
fn main() {
println!("Hello, world!");
strspilit("Hello Huge World".to_string());
}
Then you will see your code is working as it should but as notices in other answers the read!() macro is only returning the string until the first white space so you should probably use another way of reading your input.

Why do I need to declare a variable at each iteration of a loop to use it?

I am learning Rust from The Book and I just finished the first exercise, the guessing game.
I use cargo to build and run my little crate.
$ cargo --version
cargo 1.37.0 (9edd08916 2019-08-02)
$ rustc --version
rustc 1.37.0 (eae3437df 2019-08-13)
Everything run fine, including release mode. Nevertheless, I do not understand a the following behaviour of Rust: I have to redeclare the variable which contains the user input at each iteration of the loop.
Since the exercise is guided step-by-step, my code is the same that the one from the book. Nevertheless, the code from the book is the following:
loop {
// Some code to display instructions.
// Reallocate a new string at each iteration!
let mut guess = String::new();
io::stdin().read_line(&mut guess)
.expect("Failed to read line");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
// Some code to check if the player found the secret number.
}
Noticing this systematic reallocation, I moved the string declaration outside the loop:
// Allocate the string once.
let mut guess = String::new();
loop {
// Some code to display instructions.
io::stdin().read_line(&mut guess)
.expect("Failed to read line");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
// Some code to check if the player found the secret number.
}
However, Rust did not appreciate this: at the second iteration of the loop, it panics every time.
Why can't I reuse the same mutable variable more than once? Do I not understand something?
EDIT: read_line does not clear the content of the previous input, but appends to it the following one.
Let's say the player enters 1 then 2, the final value of guess will be "1\n2\n".
However, trim() removes the "blank" characters at the beginning and the end of the string, leaving a \n in the middle: parse() panics!
Your code as-is compiles and runs fine on my setup (same version of rust). The panic must happen in the commented-out part of your code. Some comments, though: the scoping in your loop is tricky: guess at the top-half of the loop is the string declared outside the loop, and is the parsed integer in the second half.
More importantly, multiple calls to read_line being passed the same string appends to the string, which probably isn't your intention given the way you're parsing the string. Sprinkling in println!'s of your guess variables should be illuminating. Your code will probably be fixed if you add a guess.clear() on the string after you've parsed the number, but to do that, you'll probably want to rename the u32 guess.
As an aside, you might consider using a BufReader and the for line in reader.lines()) pattern described here.

Resources