Guessing game, error on shadowing guess bind - rust

I'm following the Rust tutorial but I'm stuck on this code (the last snippet in the page):
extern crate rand;
use std::io;
use std::cmp::Ordering;
use rand::Rng;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1, 101);
println!("The secret number is {}", secret_number);
loop {
println!("Please input your guess");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
let guess: u32 = guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
}
println!("You guessed: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
}
}
}
When I run cargo run I have the following error:
src/main.rs:23:47: 23:48 error: expected one of `.`, `;`, or an operator, found `{`
src/main.rs:23 let guess: u32 = guess.trim().parse() {
^
What's the right syntax?

There is a syntax error and the compiler message is directing your attention to the wrong place on the line to fix the problem.
The parse method evaluates to a value. This expression should not be followed by a block, causing the syntax error reported by the compiler.
https://doc.rust-lang.org/std/string/struct.String.html#method.parse
The example you linked to has the keyword match between the assignment and call to parse. The match keyword takes an expression and branches based on the value of the expression. The block contains the branching patterns and expressions. In this case it is also destructuring the Result into either an u32 or u32::Err.
https://doc.rust-lang.org/book/match.html
Below is an example that separates the parse and match for clarity.
// Store result of parsing in a variable
let parse_result = guess.trim().parse();
// Destructure the result
let guess: u32 = match parse_result {
// If parse succeeded evaluate to the number
Ok(num) => num,
// If parse failed repeat the loop
Err(_) => continue,
};

You forgot to add the match keyword before calling guess.trim().parse()
That line should look like this:
let guess : u32 = match guess.trim().parse() {...
source: https://doc.rust-lang.org/book/ch02-00-guessing-game-tutorial.html

Related

Why is my code failling in Rust when I don't declare a variable in the loop

Code that fails
use std::cmp::Ordering;
use std::io;
use rand::Rng;
fn main() {
println!("Guess the Number!");
let mut guess = String::new();
let secret_number = rand::thread_rng().gen_range(1..10);
loop {
println!("Please input the guess.");
io::stdin().read_line(&mut guess).expect("Failed to read line");
let guess: u32 = guess.trim().parse().expect("Please Type a Number");
println!("You guessed: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too Small!"),
Ordering::Greater => println!("Too Large!"),
Ordering::Equal => println!("You got this"),
}
}
}
Code that works
use std::cmp::Ordering;
use std::io;
use rand::Rng;
fn main() {
println!("Guess the Number!");
let secret_number = rand::thread_rng().gen_range(1..10);
loop {
println!("Please input the guess.");
//Now Defining guess Inside the loop
let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("Failed to read line");
let guess: u32 = guess.trim().parse().expect("Please Type a Number");
println!("You guessed: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too Small!"),
Ordering::Greater => println!("Too Large!"),
Ordering::Equal => println!("You got this"),
}
}
}
From what I can understand, defining guess each time the loop runs makes my code work, otherwise, I get the error shown below
Why does this happen, I am entering integers only so I should not get a data type mismatch, and why does it work as soon as I start defining guess, again and again, I think this has something to do with how rust handle spaces or newline in input, but not sure.
Any help would be appreciated
Error
It failed because each time when you read_line it will append the stdin buffer to the guess string. So guess will change as following.
1\n -> 1\n2\n -> 1\n2\n3\n
To fix this issue, clear the guess variable in each loop.
use std::cmp::Ordering;
use std::io;
use rand::Rng;
fn main() {
println!("Guess the Number!");
let mut guess = String::new();
let secret_number = rand::thread_rng().gen_range(1..10);
loop {
println!("Please input the guess.");
io::stdin().read_line(&mut guess).expect("Failed to read line");
// I renamed it to a different name. Because I want to access the guess string in the end of the loop
let guess_nmb: u32 = guess.trim().parse().expect("Please Type a Number");
println!("You guessed: {}", guess_nmb);
match guess_nmb.cmp(&secret_number) {
Ordering::Less => println!("Too Small!"),
Ordering::Greater => println!("Too Large!"),
Ordering::Equal => println!("You got this"),
}
// Clear the guess string
guess.clear();
}
}

How to overwrite mutable string inside a loop?

My example is slightly modified from the guessing game tutorial in The Rust Book.
After the first iteration, the loop does not appear to read in the user input to the mutable string correctly.
Can you please identify what is wrong in the below code with regards to mut input_text?
extern crate rand;
use rand::Rng;
use std::cmp::Ordering;
use std::io;
fn main() {
let random_number = rand::thread_rng().gen_range(1, 51);
let mut input_text = String::new(); // Works fine if allocated inside loop
loop {
println!("Enter your guess:");
io::stdin()
.read_line(&mut input_text)
.expect("Failed to read input");
let input_number: u32 = match input_text.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
println!(
"You entered {} which converted to u32 is {}",
input_text, input_number
);
match input_number.cmp(&random_number) {
Ordering::Greater => println!("Input > Random"),
Ordering::Less => println!("Input < Random"),
Ordering::Equal => println!("Input == Random"),
}
}
}
As #Jmb mentioned in the comments, read_line doesn't overwrite the String but appends to it. If you'd like to overwrite the String you have to first call clear on it like so:
use rand::Rng;
use std::cmp::Ordering;
use std::io;
fn main() {
let random_number = rand::thread_rng().gen_range(1, 51);
let mut input_text = String::new();
loop {
println!("Enter your guess:");
// clear input_text from previous loop iteration
input_text.clear();
io::stdin()
.read_line(&mut input_text)
.expect("Failed to read input");
let input_number: u32 = match input_text.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
println!(
"You entered {} which converted to u32 is {}",
input_text.trim(), input_number
);
match input_number.cmp(&random_number) {
Ordering::Greater => println!("Input > Random"),
Ordering::Less => println!("Input < Random"),
Ordering::Equal => {
println!("Input == Random");
break; // break on win condition
},
}
}
}
Also your program was an infinite loop so I added a break on the win condition.

Why does Rust appear to execute statements/expressions out of order when using `print!`? [duplicate]

I'm having some problems with some basic I/O stuff. Specifically, the text "Please enter your name" is written to the output after I type in my name and hit Enter:
use std::io;
fn main() {
print!("Please enter your name: ");
let mut name = String::new();
match io::stdin().read_line(&mut name) {
Ok(_) => println!(""),
Err(err) => println!("Could not parse input: {}", err)
}
println!("Hello, {}!", name.trim());
}
gives the following output:
Compiling chat v0.1.0 (file:///home/marcus/dev/rust/chat)
Running `target/debug/chat`
marcus
Please enter your name:
Hello, marcus!
Where the first "marcus" was entered by me. Why won't the program print "Please enter your name" before waiting for input?
Is it possible to "do nothing" if a returned Result is Ok? In the example, Ok() means that I have saved the input in the variable name. That's great. But what do I do with Ok() => in this case?
Why won't the program print "Please enter your name" before waiting for input?
Well, it did. It's just that, for performance reasons, standard output is buffered. The write completed, but it was only writing to memory. If you want it to actually display to the user, you have to trigger a flush. This can be done either by writing a newline, or by doing it explicitly:
io::Write::flush(&mut io::stdout()).expect("flush failed!");
// If you "use" `io::Write`...
io::stdout().flush().expect("flush failed!");
Also, is it possible to "do nothing" if a returned Result is Ok?
Sure. Just... do nothing.
match io::stdin().read_line(&mut name) {
Ok(_) => { /* nothing */ },
Err(err) => println!("Could not parse input: {}", err)
}
The relevant requirement here is that all arms in a match have to have the same result type. In the case of println!, it results in a (); aside from an empty block (or another function that returns ()), you can just use a literal:
match io::stdin().read_line(&mut name) {
Ok(_) => (),
Err(err) => println!("Could not parse input: {}", err)
}
This is explained on the documentation for print!. Since print! does not emit a newline and stdout is line-buffered, you won't see any output. You can manually flush stdout:
use std::io::{self, Write};
print!("Please enter your name: ");
io::stdout().flush();
For your second question you can always return unit explicitly:
Ok(_) => (),
So your program becomes:
use std::io::{self, Write};
fn main() {
print!("Please enter your name: ");
io::stdout().flush();
let mut name = String::new();
match io::stdin().read_line(&mut name) {
Ok(_) => (),
Err(err) => println!("Could not parse input: {}", err)
}
println!("Hello, {}!", name.trim());
}
As #Veedrac pointed out in their (now deleted) comment, you can use an if let expression in place of the match on the result of read_line:
if let Err(err) = io::stdin().read_line(&mut name) {
println!("Could not parse input: {}", err)
}
use std::io::{self, Write};
fn main() {
print!("Please enter your name: ");
let _ = io::stdout().flush();
// your io code
}

How does Rust handle shadowed variables?

I have strong C/C++ background and am learning Rust these days. Got puzzled by how Rust handles shadowing variables. Particularly, I was expecting that the following code segment shall run without problem because guess is shadowed from a String to an integer before the next time it is called as a String in read_line.
Reading the API document, I understand read_line would append the next input to guess. But after the shadowing, should guess be considered as an integer and such appending be invalid? Please help.
fn main() {
let secret_number = 10;
let mut guess = String::new();
loop {
//guess.clear(); // uncomment this line will make it work.
println!("Please input your guess:");
io::stdin()
.read_line(&mut guess)
.expect("Failed to read guess.");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
};
}
}
Shadowing is a purely syntactic phenomenon. It has no effect in the generated code, that is the generated code would be identical if you chose a different name for each variable. It is just that the shadowed variable cannot be referenced by name.
In particular, in your code:
let mut guess = String::new(); //1
...
loop {
io::stdin().read_line(&mut guess)... //2
let guess: u32 = match guess.trim()... ; //3
match guess.cmp(...) // 4
}
//5
The usages in line 2 and 3 refer to the declared variable in line 1, while the usage in line 4 refers to the declaration in line 3. There is no change in the type of the variable, nor there is any change in lifetimes. Simply they are two different variables that happen to have the same name, so that it will be impossible for your program to access the variable in line 1 from line 4.
In fact, after the loop finises, in line 5, the name guess will again refer to the variable in line 1, because the other one went out of scope.

Why does this read input before printing?

I'm having some problems with some basic I/O stuff. Specifically, the text "Please enter your name" is written to the output after I type in my name and hit Enter:
use std::io;
fn main() {
print!("Please enter your name: ");
let mut name = String::new();
match io::stdin().read_line(&mut name) {
Ok(_) => println!(""),
Err(err) => println!("Could not parse input: {}", err)
}
println!("Hello, {}!", name.trim());
}
gives the following output:
Compiling chat v0.1.0 (file:///home/marcus/dev/rust/chat)
Running `target/debug/chat`
marcus
Please enter your name:
Hello, marcus!
Where the first "marcus" was entered by me. Why won't the program print "Please enter your name" before waiting for input?
Is it possible to "do nothing" if a returned Result is Ok? In the example, Ok() means that I have saved the input in the variable name. That's great. But what do I do with Ok() => in this case?
Why won't the program print "Please enter your name" before waiting for input?
Well, it did. It's just that, for performance reasons, standard output is buffered. The write completed, but it was only writing to memory. If you want it to actually display to the user, you have to trigger a flush. This can be done either by writing a newline, or by doing it explicitly:
io::Write::flush(&mut io::stdout()).expect("flush failed!");
// If you "use" `io::Write`...
io::stdout().flush().expect("flush failed!");
Also, is it possible to "do nothing" if a returned Result is Ok?
Sure. Just... do nothing.
match io::stdin().read_line(&mut name) {
Ok(_) => { /* nothing */ },
Err(err) => println!("Could not parse input: {}", err)
}
The relevant requirement here is that all arms in a match have to have the same result type. In the case of println!, it results in a (); aside from an empty block (or another function that returns ()), you can just use a literal:
match io::stdin().read_line(&mut name) {
Ok(_) => (),
Err(err) => println!("Could not parse input: {}", err)
}
This is explained on the documentation for print!. Since print! does not emit a newline and stdout is line-buffered, you won't see any output. You can manually flush stdout:
use std::io::{self, Write};
print!("Please enter your name: ");
io::stdout().flush();
For your second question you can always return unit explicitly:
Ok(_) => (),
So your program becomes:
use std::io::{self, Write};
fn main() {
print!("Please enter your name: ");
io::stdout().flush();
let mut name = String::new();
match io::stdin().read_line(&mut name) {
Ok(_) => (),
Err(err) => println!("Could not parse input: {}", err)
}
println!("Hello, {}!", name.trim());
}
As #Veedrac pointed out in their (now deleted) comment, you can use an if let expression in place of the match on the result of read_line:
if let Err(err) = io::stdin().read_line(&mut name) {
println!("Could not parse input: {}", err)
}
use std::io::{self, Write};
fn main() {
print!("Please enter your name: ");
let _ = io::stdout().flush();
// your io code
}

Resources