book icon indicating copy to clipboard operation
book copied to clipboard

Example listing-09-13 works even using Guess { value: guess } instead Guess::new(guess)

Open tomaslucas opened this issue 2 years ago • 1 comments

  • I have searched open and closed issues and pull requests for duplicates, using these search terms:
    • listing-09-13
    • listing 09-13
    • 9-13
  • I have checked the latest main branch to see if this has already been fixed, in this file:
    • Yes

URL to the section(s) of the book with this problem: https://doc.rust-lang.org/book/ch09-03-to-panic-or-not-to-panic.html https://github.com/rust-lang/book/blob/main/listings/ch09-error-handling/listing-09-13/src/main.rs Description of the problem: The text under the example says:

This public method is necessary because the value field of the Guess struct is private. It’s important that the value field be private so code using the Guess struct is not allowed to set value directly: code outside the module must use the Guess::new function to create an instance of Guess, thereby ensuring there’s no way for a Guess to have a value that hasn’t been checked by the conditions in the Guess::new function.

But if you call Guess { value: guess } instead Guess::new(guess) it works without errors.

Suggested fix:

use rand::Rng;
use std::cmp::Ordering;
use std::io;

use crate::guess_module::Guess;

// ANCHOR: here
pub mod guess_module {
    pub struct Guess {
        value: i32,
    }

    impl Guess {
        pub fn new(value: i32) -> Guess {
            if value < 1 || value > 100 {
                panic!("Guess value must be between 1 and 100, got {}.", value);
            }

            Guess { value }
        }

        pub fn value(&self) -> i32 {
            self.value
        }
    }
}
// ANCHOR_END: here

fn main() {
    println!("Guess the number!");

    let secret_number = rand::thread_rng().gen_range(1..=100);

    loop {
        println!("Please input your guess.");

        let mut guess = String::new();

        io::stdin()
            .read_line(&mut guess)
            .expect("Failed to read line");

        let guess: i32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => continue,
        };

        // This way to create a guess will work
        let guess = Guess::new(guess);
        // If you uncomment the next line instead the previous one we will have an error
        // let guess = Guess { value: guess };

        match guess.value().cmp(&secret_number) {
            Ordering::Less => println!("Too small!"),
            Ordering::Greater => println!("Too big!"),
            Ordering::Equal => {
                println!("You win!");
                break;
            }
        }
    }
}

tomaslucas avatar Oct 12 '23 19:10 tomaslucas

Hi @tomaslucas, thanks for the issue! You're correct: we are not actually wrapping that in a module so it is not private. I've flagged this up for us to tackle in working on the 2024 revision.

chriskrycho avatar Mar 29 '24 15:03 chriskrycho