Rust Beginner: แบนแมตช์ที่ซ้อนกัน

Sep 20 2020

นี่คือวิธีที่ฉันใช้เกมทายใจ - บทที่ 2 ของหนังสือ Rust: https://doc.rust-lang.org/book/ch02-00-guessing-game-tutorial.html

use std::io;
use std::io::Error;
use std::cmp::Ordering;
use std::num::ParseIntError;

use rand::Rng;


enum MyReadLineError {
    FailReadLine(Error)
}

#[derive(Debug)]
enum MyReadU32Line {
    FailReadLine(Error),
    FailParse(ParseIntError)
}


fn my_read_line() -> Result<String, MyReadLineError> {
    let mut input = String::new();
    let result = io::stdin().read_line(&mut input);
    match result {
        Ok(_) => Ok(input),
        Err(error ) => Err(MyReadLineError::FailReadLine(error)),
    }
}

fn my_read_u32_line() -> Result<u32, MyReadU32Line> {
    match my_read_line() {
        Result::Ok(line) =>
            match line.trim().parse::<u32>() {
                Ok(value) => Ok(value),
                Err(error) => Err(MyReadU32Line::FailParse(error)),
            }

        Result::Err(MyReadLineError::FailReadLine(error)) => Err(MyReadU32Line::FailReadLine(error)),
    }
}

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

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

    loop {
        println!("Please input your guess.");
        let guess = my_read_u32_line();
        match guess {
            Ok (value) => match value.cmp(&secret_number) {
                Ordering::Less => println!("Too small!"),
                Ordering::Greater => println!("Too big!"),
                Ordering::Equal => {
                    println!("You win!");
                    break;
                },
            }
            Err (_) => println!("Sorry I couldn't read a u32 from your input! Please try again."),
        }
    }
}

สิ่งนี้ได้ผลตามที่คาดไว้ แต่ฉันต้องการทำให้การแข่งขันเรียบเพื่อไม่ให้ดูละเอียดเป็นไปได้ นอกจากนี้ยังมีวิธีอื่นใดที่จะทำให้โค้ดนั้นดูดีขึ้นอ่านง่ายขึ้น

คำตอบ

7 L.F. Sep 20 2020 at 21:04

ยินดีต้อนรับสู่ Rust!

การจัดรูปแบบรหัส

มีบางอย่างที่ไม่สอดคล้องกันในการจัดรูปแบบของคุณ - ฉันได้เรียกใช้cargo fmtเพื่อกำจัดสิ่งเหล่านี้

การตั้งชื่อ

ไม่จำเป็นต้องใส่คำนำหน้าทุกอย่างด้วยMyหรือmy_- ใน Rust ชื่อของคุณจะไม่ขัดแย้งกับชื่อที่มีอยู่อย่างง่ายดายเช่นเดียวกับในภาษาอื่น ๆ

การจัดการข้อผิดพลาด

สำหรับแอปพลิเคชันฉันขอแนะนำให้ใช้anyhowลังเพื่อจัดการข้อผิดพลาดซึ่งจะช่วยลดจำนวนสำเร็จรูปได้มาก เพียงแค่เพิ่ม

anyhow = "1.0"

ไปที่[dependencies]ส่วนของCargo.tomlไฟล์.

ฟังก์ชันตัวช่วย

my_read_lineฟังก์ชั่นได้ง่ายกับ?ผู้ประกอบการ:

use anyhow::Result;

fn read_line() -> Result<String> {
    let mut input = String::new();
    io::stdin().read_line(&mut input)?;
    Ok(input)
}

my_read_u32_line สามารถทำให้ง่ายขึ้นในทำนองเดียวกัน:

fn read_u32() -> Result<u32> {
    Ok(read_line()?.trim().parse()?)
}

ตัวเลขมหัศจรรย์

เราสามารถกำหนดค่าคงที่สำหรับช่วงของตัวเลข:

const MIN: u32 = 1;
const MAX: u32 = 100;

// later
let secret_number = rand::thread_rng().gen_range(MIN, MAX + 1);

องค์กร

ฉันอาจจัดระเบียบmainฟังก์ชันใหม่เพื่อลดการเยื้อง:

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

    let guess = match read_u32() {
        Ok(guess) => guess,
        Err(_) => {
            println!(
                "Sorry I couldn't read a u32 from your input! \
                Please try again."
            );
            continue;
        }
    };

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

ผลลัพธ์สุดท้าย

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

const MIN: u32 = 1;
const MAX: u32 = 100;

fn read_line() -> Result<String> {
    let mut input = String::new();
    io::stdin().read_line(&mut input)?;
    Ok(input)
}

fn read_u32() -> Result<u32> {
    Ok(read_line()?.trim().parse()?)
}

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

    let secret_number = rand::thread_rng().gen_range(MIN, MAX + 1);

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

        let guess = match read_u32() {
            Ok(guess) => guess,
            Err(_) => {
                println!(
                    "Sorry I couldn't read a u32 from your input! \
                    Please try again."
                );
                continue;
            }
        };

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