1

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"),
        }
    }
}
4
  • 2
    Each time you call read_line, you append to the existing string. Try calling input_text.clear() before reading. Commented Jun 26, 2020 at 12:09
  • The easiest solution is actually to move the declarationg of input_text inside the loop. You noticed yourself that this makes your code work, and the additional allocation really doesn't matter in this case. Commented Jun 26, 2020 at 12:12
  • 2
    Thank you @Jmb. I should've looked up the API doc [doc.rust-lang.org/std/io/struct.Stdin.html#method.read_line]. From the API name, it seemed like it would just overwrite. Commented Jun 26, 2020 at 13:09
  • 1
    @SvenMarnach, the repeated allocation probably doesn't mater in this example. But surely, we don't want to do it in non-trivial programs when the memory usage is higher? Commented Jun 26, 2020 at 13:22

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.