mut Переопределение строки внутри цикла

Я читаю книгу о Rust, и в руководстве по игре в угадайку есть следующий код:

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

fn main() {
    let secret_number = rand::thread_rng().gen_range(1, 101);
    let mut input = String::new();

    loop {
        print!("Guess the number I'm thinking of: ");
        io::stdout().flush().unwrap();
        io::stdin().read_line(&mut input).expect("Failed to read line");

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

        println!("\nYou guessed: {}", guess);

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

Этот код не работает после первого ввода пользователя. Если я перемещу объявление let mut input = String::new(); внутрь цикла, тогда все в порядке ... Но мне интересно, почему я должен это делать, если адрес input передается в read_line()?

И еще одна вещь, почему я должен использовать std::io::Write, чтобы использовать io::stdout().flush().unwrap();, если я уже использую use std::io;?


person syd619    schedule 23.01.2021    source источник


Ответы (1)


io::stdin().read_line(&mut input);

Этот метод не перезаписывает String, но добавляет к String. Вот почему работает только первая итерация цикла, но она сразу же прерывается на второй итерации. Если вы хотите повторно использовать буфер String между итерациями, вам необходимо обрезать его перед передачей обратно в _ 5_. Исправленный рабочий пример:

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

fn main() {
    let secret_number = rand::thread_rng().gen_range(1, 101);
    let mut input = String::new();

    loop {
        print!("Guess the number I'm thinking of:");
        io::stdout().flush().unwrap();
        
        input.clear(); // truncate String buffer here!

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

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

        println!("\nYou guessed: {}", guess);

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

И еще одна вещь: почему я должен использовать std::io::Write, чтобы использовать io::stdout().flush().unwrap();, если я уже использую std::io;?

Чтобы вызвать методы трейта, вам нужно включить трейт в область видимости. flush определяется тегом _ 11_ черта.

person pretzelhammer    schedule 24.01.2021