Hoàn thiện game Đoán số với Rust: Sử dụng Loop, Break và xử lý lỗi

07 tháng 4, 2026·5 phút đọc

Trong phần cuối cùng của series hướng dẫn Rust, chúng ta sẽ hoàn thiện trò chơi đoán số bằng cách thêm vòng lặp vô tận, điều kiện thoát khi chiến thắng và xử lý các đầu vào không hợp lệ một cách mượt mà.

Hoàn thiện game Đoán số với Rust: Sử dụng Loop, Break và xử lý lỗi

Chào mừng bạn đến với phần cuối của loạt bài hướng dẫn xây dựng trò chơi đoán số với ngôn ngữ lập trình Rust. Trong bài viết này, chúng ta sẽ tập trung vào các khái niệm điều khiển luồng quan trọng để biến chương trình đơn lẻ thành một vòng lặp game hoàn chỉnh.

Dưới đây là những điểm kiến thức cốt lõi mà chúng ta sẽ khám phá:

  • Vòng lặp vô tận với loop
  • Thoát vòng lặp với break
  • Bỏ qua lần lặp hiện tại với continue
  • Ứng dụng linh hoạt của match
  • Cách xử lý kiểu liệt kê (enum) và lỗi đầu vào

Mục tiêu của trò chơi

Trước khi đi vào chi tiết mã nguồn, hãy nhắc lại các yêu cầu mà game cần đạt được:

  • Tạo ngẫu nhiên một số từ 1 đến 100.
  • Nhắc người chơi nhập vào một con số để đoán.
  • Sau khi người chơi đoán, chương trình sẽ thông báo số đó lớn hơn hay nhỏ hơn số bí mật.
  • Quan trọng nhất: Tiếp tục yêu cầu người chơi đoán cho đến khi đúng. Nếu đoán đúng, in lời chúc mừng và thoát chương trình.

Triển khai mã nguồn

Bước 1: Thêm vòng lặp (Loop)

Ở phần trước, mã nguồn của chúng ta chỉ thực hiện quá trình đoán đúng một lần. Để game có thể chơi lại nhiều lần, chúng ta cần lặp lại các bước từ việc yêu cầu nhập, so sánh cho đến khi in ra kết quả.

Đoạn mã cần được thực hiện lặp lại bao gồm:

println!("Guess a number");

let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("Could not read the line");

let guess:u32 = guess.trim().parse().expect("Please enter a number");

println!("The number you guessed is:{}", guess);

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

Rust cung cấp từ khóa loop để tạo ra một vòng lặp vô tận. Cấu trúc của nó rất đơn giản:

loop {
    // Mã lệnh bạn muốn lặp đi lặp lại mãi mãi
}

Bây giờ, hãy đặt toàn bộ logic xử lý đoán số vào bên trong khối loop này:

loop {
    println!("Guess a number");

    let mut guess = String::new();
    io::stdin().read_line(&mut guess).expect("Could not read the line");

    let guess:u32 = guess.trim().parse().expect("Please enter a number");

    println!("The number you guessed is:{}", guess);

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

Bước 2: Điều kiện thoát chương trình

Tuy nhiên, đoạn mã trên có một vấn đề lớn: nó sẽ yêu cầu người chơi nhập liệu mãi mãi và không bao giờ dừng lại. Về mặt logic, sau khi người chơi đoán đúng và chương trình in ra thông báo "You win", nó nên dừng lại.

Đây là lúc chúng ta cần đến từ khóa break, được dùng để thoát khỏi vòng lặp. Hãy thêm nó vào nhánh Ordering::Equal.

Lưu ý: Nếu bạn muốn thực thi nhiều dòng lệnh trong một nhánh của match, bạn cần bọc chúng trong một cặp dấu ngoặc nhọn {}.

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

Bước 3: Xử lý đầu vào không hợp lệ

Vẫn còn một thiếu sót trong mã nguồn: nếu người chơi nhập một ký tự không phải là số (ví dụ: "abc"), hàm .parse() sẽ trả về lỗi Err. Khi .expect() nhận được lỗi này, toàn bộ chương trình sẽ sụp đổ (crash) ngay lập tức.

Logic đúng đắn ở đây应该是: nếu nhập sai, hãy in thông báo lỗi và yêu cầu người chơi nhập lại, chứ không dừng game.

Để làm điều này, chúng ta cần hiểu rằng .parse() trả về một enum type. Nếu chuyển đổi thành công, nó trả về Ok chứa nội dung đã chuyển đổi; nếu thất bại, nó trả về Err chứa lý do lỗi.

Chúng ta đã từng làm việc với enum Ordering ở bài trước và dùng match để xử lý các trường hợp. Tại đây, ta cũng dùng match để xử lý kết quả của .parse(): nếu thành công thì tiếp tục, nếu thất bại thì bỏ qua đoạn code dưới và chuyển sang lần lặp tiếp theo. Trong Rust, từ khóa để bỏ qua vòng lặp hiện tại là continue.

Hãy thay thế dòng code:

let guess:u32 = guess.trim().parse().expect("Please enter a number");

Bằng đoạn code sử dụng match sau:

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

Giải thích chi tiết:

  • Ok(num) => num: Nhánh này xử lý khi chuyển đổi thành công. Ok là một biến thể của enum. Bên trong dấu ngoặc () sau Ok là nội dung số đã chuyển đổi (u32). Việc viết num ở đây có nghĩa là chúng ta gán nội dung đó cho biến num. Giá trị của num sẽ được trả về làm kết quả của biểu thức match và gán cho guess.
  • Err(_) => continue: Nhánh này xử lý khi chuyển đổi thất bại. Err là một biến thể khác. Dấu gạch dưới _ bên trong () có nghĩa là chúng ta không quan tâm đến thông điệp lỗi cụ thể là gì, chỉ cần biết là có lỗi là đủ. Khi đó, continue sẽ được gọi để bắt đầu vòng lặp mới.

Việc sử dụng match thay vì .expect() để xử lý lỗi là một phương pháp rất phổ biến và idiomatically trong Rust.

Kết quả mã nguồn hoàn chỉnh

Dưới đây là toàn bộ mã nguồn của trò chơi sau khi đã hoàn thiện:

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

fn main() {
    let range_number = rand::thread_rng().gen_range(1..101);

    println!("Number Guessing Game");

    loop {
        println!("Guess a number");

        let mut guess = String::new();
        io::stdin().read_line(&mut guess).expect("Could not read the line");

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

        println!("The number you guessed is:{}", guess);

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

    println!("The secret number is: {}", range_number);
}

Khi chạy chương trình, bạn sẽ thấy game hoạt động trơn tru, cho phép đoán lại cho đến khi thắng và bỏ qua các đầu vào không phải là số.

Kết quả chạy chương trìnhKết quả chạy chương trình

Chúc mừng bạn đã hoàn thành xong trò chơi đoán số cơ bản với Rust!

Bài viết được tổng hợp và biên soạn bằng AI từ các nguồn tin tức công nghệ. Nội dung mang tính tham khảo. Xem bài gốc ↗