Why does it panic?


#1

The following code compiles fine and then panics at run time.

use std::io;

fn main() {
    let number = 5;
    let mut guess = String::new();

    loop {
        println!("Guess the number!");
        io::stdin().read_line(&mut guess)
            .expect("Failed to read line");
        println!("You guessed: {}", guess);
        let guess: u32 = guess.trim().parse()
            .expect("Please type a number!");
        if guess == number {
           break;
        }
    }
}

When I run ‘cargo run’, this is what happens:

Guess the number!
45
You guessed: 45

Guess the number!
32
You guessed: 45
32

thread 'main' panicked at 'Please type a number!: ParseIntError { kind: InvalidDigit }', /checkout/src/libcore/result.rs:86

This is strange because the only things I have typed are all digits: 45 and then 32, apart from the two newlines. Shouldn’t the newline be removed by trim()?

The stack trace ends with:

  13: std::rt::lang_start
         at /checkout/src/libstd/panicking.rs:433
         at /checkout/src/libstd/panic.rs:361
         at /checkout/src/libstd/rt.rs:59
  14: main
  15: __libc_start_main
  16: _start

Everything above that is the panic winding its way. Not much useful info here.

Details:
Ubuntu 16.04, rustc 1.19.0, cargo 0.20.0,
cc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609 [gcc 5.4]

Cargo.toml:

[package]
name = "hello"
version = "0.1.0"
authors = [“ubuntu”]

[dependencies]


#2

You’re accumulating multiple inputs into the same “guess” variable, including the newlines. Try moving the declaration of guess into the loop.


#3

You are right! The definition of read_line is:
Read all bytes until a newline (the 0xA byte) is reached, and **append** them to the provided buffer.

Thanks.


#4

Alternatively, call clear() at the start of the loop. This lets you re-use the String rather than creating a new one every time.


#5

Thanks, Steve. I did wind up calling clear().