What program shoud do?
- Read two numbers separated by space from terminal e.g. "10 8".
- Split the string to
Vec<&str>
. - Parse
Vec[0]
andVec[1]
tonum1
andnum2
. - Read (math) operation from terminal and parse it.
- Print the "math" and result. (10 * 80 = 80)
- Catch almost every error in steps 2. - 4. and run
try_again
function. - If all goes right than run
try_again
function with "Success"msg
(the main
function is there only for context,
the problem is in try_again
function)
use std::io::{self, Write, Read, Error, ErrorKind};
const ERR_MSG_STDIN_READ: &str = "Problem with getting input";
const ERR_MSG_STDOUT_FLUSH: &str = "Problem with flushing stdout";
fn main() {
loop {
clear_terminal();
print!("Write 2 ints separated by space: ");
let mut nums_string = String::new();
io::stdout().flush().expect(ERR_MSG_STDOUT_FLUSH);
io::stdin().read_line(&mut nums_string).expect(ERR_MSG_STDIN_READ);
let nums_str_vec: Vec<&str> = nums_string.trim()
.split(' ').collect();
let num1: i32 = match nums_str_vec[0].parse() {
Ok(num) => num,
Err(_) => match try_again("Error") {
true => continue,
false => break
}
};
let num2: i32 = match nums_str_vec[1].parse() {
Ok(num) => num,
Err(_) => match try_again("Error") {
true => continue,
false => break
}
};
print!("Write one of these[ ,-,*,/] maths operation for 2 inputed ints: ");
let mut operation_string = String::new();
io::stdout().flush().expect(ERR_MSG_STDOUT_FLUSH);
io::stdin().read_line(&mut operation_string).expect(ERR_MSG_STDIN_READ);
let operation = match operation_string.trim().parse() {
Ok(char) => char,
Err(_) => match try_again("Error") {
true => continue,
false => break
}
};
match operation {
' ' => println!("{} {} {} = {}", num1, operation, num2, num1 num2),
'-' => println!("{} {} {} = {}", num1, operation, num2, num1 - num2),
'*' => println!("{} {} {} = {}", num1, operation, num2, num1 * num2),
'/' => println!("{} {} {} = {} ({})", num1, operation, num2, num1 / num2, num1 % num2),
_ => match try_again("Error") {
true => continue,
false => break
}
}
io::stdin().read(&mut [0]).expect(ERR_MSG_STDIN_READ);
match try_again("Success") {
true => continue,
false => break
}
}
}
fn clear_terminal() {
print!("{}c", 27 as char);
io::stdout().flush().expect(ERR_MSG_STDOUT_FLUSH);
}
What try_again
function shoud do?
- Save
msg
tomsg_new
for later changing. - Read (y/n) answer from terminal and parse it.
- If 'y' return
true
if 'n' returnfalse
. - Catch almost every error in step 2. and continue "self loop" again. (With "Error"
msg
) - The program (in
main
function) match returned result oftry_again
function => true means continue main loop, false means break the loop and end the program.
fn next(msg: &str) -> bool {
let mut msg_new = msg;
loop {
println!("The calculation end up with {}.", msg_new);
print!("Do you want to make antoher calculation? (y/n): ");
let mut next_string = String::new();
stdout().flush().expect(ERR_MSG_STDOUT_FLUSH);
stdin().read_line(&mut next_string).expect(ERR_MSG_STDIN_READ);
match next_string.trim().parse() {
Ok('y') => true,
Ok('n') => false,
_ => {
msg_new = "Error";
continue
}
};
}
}
Whats the problem?
What doesn´t work in program?
step 7 (maybe we can say 6 and 7) the problem is in try_again
function.
What doesn´t work in try_again
function
When the program run try_again("Success");
:
- In the first loop
stdin().read_line(&mut next_string)
doesn´t wait for users input and immediately go to_ =>
arm. - And continue "self loop" again (with "Error"
msg
) - In the second loop actually wait for input and work but with wrong
msg
.
Final question
Why the stdin().read_line(&mut next_string)
wait for input in secodn round of loop? How to solve it? Thanks for every answer!
I am totally new to rust, please explain everything what you write. OS: Windows 10, terminal: cmd (Command Promt)
CodePudding user response:
You must check whether a 'y'
or a 'n'
was entered at all, e.g. with a guard:
fn next(msg: &str) -> bool {
let msg_new = msg;
loop {
clear_terminal();
println!("The calculation end up with {}.", msg_new);
print!("Do you want to make antoher calculation? (y/n): ");
let mut next_string = String::new();
stdout().flush().expect(ERR_MSG_STDOUT_FLUSH);
match std::io::stdin().read_line(&mut next_string) {
Ok(n) if n > 0 && next_string.chars().next().unwrap() == 'y' => break true,
Ok(n) if n > 0 && next_string.chars().next().unwrap() == 'n' => break false,
Ok(_) => {}, // other input is ignored
Err(err) => panic_any(err),
};
}
}
Btw: next
should be reserved for iterators
CodePudding user response:
When you enter y or n, the program does not go to the match arm with continue
.
It sets the return value of the match
statement to either true
or false
(which is never stored in a variable though) and then goes to the next iteration of the loop.
I guess you would actually like to return the boolean values from the next
function in these match arms as shown below:
fn next(msg: &str) -> bool {
let mut msg_new = msg;
loop {
clear_terminal();
println!("The calculation end up with {}.", msg_new);
print!("Do you want to make antoher calculation? (y/n): ");
let mut next_string = String::new();
stdout().flush().expect(ERR_MSG_STDOUT_FLUSH);
stdin().read_line(&mut next_string).expect(ERR_MSG_STDIN_READ);
match next_string.trim().parse() {
Ok('y') => return true,
Ok('n') => return false,
_ => {
msg_new = "Error";
continue
}
};
}
}