Search code examples
ruststdio

Reading stdin error multiple times in a row with Rust


I am just starting to learn Rust and I am trying to create a guessing game. However, I keep running into an error where reading from the stdin captures all previous inputs to stdin as well. I am running this on Windows 10.

My actual guessing game program thing:

use std::{io};

use rand::Rng;

fn main() {
    let mut rng = rand::thread_rng();
    let x: u8 = rng.gen_range(0..=10);

    let mut end_game: bool = false;

    println!("Welcome to the number guessing game");
    println!("After each guess, I'll let you know if you're too high or too low");

    let mut guess: String = String::new();
    let mut guess_int: u8;
    while !end_game {
        println!("Guess: ");
        io::stdin().read_line(&mut guess).expect("Failed to read input");
        println!("You guessed {guess}");

        guess_int = guess.trim().parse().unwrap();

        if guess_int == x {
            end_game = true;
        } else if guess_int > x {
            println!("{} is too high!", guess_int);
        } else if guess_int < x {
            println!("{} is too low", guess_int);
        }
    }

    println!("You got it!");

}

And then here is another rust file that I wrote to just make sure the problem I assumed was happening is happening.

use std::io;

fn main() {
    let mut input: String = String::new();

    println!("what is your name?");
    io::stdin().read_line(&mut input).expect("!!");

    println!("Input1: {input}");

    println!("age?");
    io::stdin().read_line(&mut input).expect("!!");

    println!("Input2: {input}");
}

Which gave me this out:

what is your name?
Input1: Joe

age?
420
Input2: Jack
420


Is there a way to flush the stdin or anything like that? Thanks in advance.


Solution

  • Thanks to both @PitaJ and @Masklinn, both of whom supplied answers.

    The issue is that std::io::stdin().read_line(...) appends to the String passed by reference to the function. As such, one must empty the String you pass in before reusing it to get input. This can be done with either String::new() or StringNameHere.clear().

    My working code ended up looking like this:

    use std::{io};
    
    use rand::Rng;
    
    fn main() {
        // println!("Hello, world! : ");
    
        let mut rng = rand::thread_rng();
        let x: u8 = rng.gen_range(0..=20);
        let mut num_guesses: u8 = 0;
    
        let mut end_game: bool = false;
    
        println!("Welcome to the number guessing game");
        println!("After each guess, I'll let you know if you're too high or too low");
    
        let mut guess: String = String::new();
        let mut guess_int: u8;
        while !end_game {
            println!("Guess: ");
            io::stdin().read_line(&mut guess).expect("Failed to read input");
    
            guess_int = guess.trim().parse().unwrap();
            guess.clear();  //guess = String::new() works too, but I think this method is easier to understand
            num_guesses += 1;
    
            if guess_int == x {
                end_game = true;
            } else if guess_int > x {
                println!("{} is too high!", guess_int);
            } else if guess_int < x {
                println!("{} is too low", guess_int);
            }
        }
    
        println!("You got it! You guessed the magic number ({}) in {} guesses", x, num_guesses);
    }