rust 除了递归,还有更好的方法来进行无限错误检查吗?

kqqjbcuj  于 2023-01-02  发布在  其他
关注(0)|答案(1)|浏览(157)

我正在尝试制作一个带有自定义棋盘尺寸的井字游戏。我希望这很难被破解,所以如果输入无效或出现错误,我使用递归来获取棋盘测量值。然而,这对我来说似乎不是很干净,我想知道是否有更好/更生疏的方法来实现同样的事情。

main函数中的代码

let board_size_str = get_board_size_string();
let (x_pos, width, height) = get_board_measurement(&board_size_str);

函数

fn get_board_size_string() -> String {
    println!("Select the size of the board in the following format: 5x5 or 7x7");
    println!("The size can be from 3x3 to 30x30");
    print!("Size: ");
    std::io::stdout().flush().expect("Failed to flush stdout!");
    let mut board_size_str = String::new();
    std::io::stdin().read_line(&mut board_size_str).expect("Failed to read board size!");
    println!();

    board_size_str
}

fn get_board_measurement(board_size_str: &str) -> (usize, i64, i64) {
    let x_pos = get_x_pos(board_size_str);
    let width = get_board_width(board_size_str, x_pos);
    let height = get_board_height(board_size_str, x_pos);

    (x_pos, width, height)
}

fn get_x_pos(board_size_str: &str) -> usize {
    let x_pos_option = board_size_str.chars().position(|c| c == 'x');

    match x_pos_option {
        Some(x_pos) => x_pos,
        None => {
            println!("Board size must contain an x!");
            let board_size_str = get_board_size_string();
            get_x_pos(&board_size_str)
        }
    }
}

fn get_board_width(board_size_str: &str, x_pos: usize) -> i64 {
    let width_result = board_size_str[..x_pos].parse::<i64>();
    
    match width_result {
        Ok(width) => width,
        Err(_) => {
            println!("Invalid board width!");
            let board_size_str = get_board_size_string();
            get_board_width(&board_size_str, get_x_pos(&board_size_str))
        }
    }
}

fn get_board_height(board_size_str: &str, x_pos: usize) -> i64 {
    let height_result = board_size_str[x_pos + 1..].trim().parse::<i64>();

    match height_result {
        Ok(height) => height,
        Err(_) => {
            println!("Invalid board height!");
            let board_size_str = get_board_size_string();
            get_board_height(&board_size_str, get_x_pos(&board_size_str))
        }
    }
}
watbbzwu

watbbzwu1#

只使用迭代循环?

fn get_x_pos(board_size_str: &str) -> usize {
    loop {
        let board_size_str = get_board_size_string();
        let x_pos_option = board_size_str.chars().position(|c| c == 'x');
        if let Some(x_pos) = x_pos_option {
            break x_pos
        }
    }
}

虽然结构很奇怪,因为正确的电路板大小是正确的模式('x'),所以将其拆分为三个不相关的例程没有任何意义,即使其中两个确实委托了x分隔符的本地化。
使用你的方法,你可以输入52xkf这样的东西,得到一个错误,输入24x36,我想你会得到一个52x36的电路板,而不是你可能期望的24x36,这很奇怪。

fn parse_board_size() -> (usize, usize) {
    loop {
        let s = get_board_size_string();
        let Some((w_s, h_s)) = s.split_once('x') else { 
            // complain about a missing `x` here
            continue;
        };
        match (w_s.parse(), h_s.parse()) {
            (Ok(w), Ok(s)) => {
                // can add more validation here,
                // or as pattern guards
                return (w, s);
            }
            (Ok(_), Err(h_error)) => {
                // h was incorrect
            }
            (Err(w_error), Ok(_)) => {
                // w was incorrect
            }
            (Err(w_error), Err(h_error)) => {
                // both were incorrect
            }
        }
    }
}

如果您不关心单独报告每个错误案例,那么您可以使用Option进行解析,例如:

fn parse_board_size() -> (usize, usize) {
    loop {
        let s = get_board_size_string();
        let Some((w_s, h_s)) = s.split_once('x') else { 
            // complain about a missing `x` here
            continue;
        };
        if let Some(r) = w_s.parse().ok().zip(h_s.parse().ok()) {
            break r;
        }
        // report generic parsing error
    }
}

相关问题