Rust Beginner : 중첩 된 매치 병합

Sep 20 2020

이것이 내가 추측 게임을 구현 한 방법입니다-Rust 책의 2 장 : 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;
            }
        };
    }
}