在体育运动中,计分规则往往比想象中更加复杂。保龄球就是这样一个例子,它的计分系统包含了多种特殊情况,如补中(spare)、全中(strike)等,这些都会影响最终得分的计算。在 Exercism 的 “bowling” 练习中,我们将实现一个完整的保龄球计分系统,这不仅能帮助我们掌握复杂状态管理技巧,还能深入学习 Rust 中的状态机设计和错误处理机制。
保龄球计分规则
保龄球比赛由10轮(frames)组成,每轮玩家最多投球2次(除非是补中或全中)。计分规则如下:
- 普通轮次:两次投球击倒的瓶数直接相加
- 补中(Spare):一轮中两次投球击倒所有10个瓶,得分为10 + 下一次投球击倒的瓶数
- 全中(Strike):第一次投球就击倒所有10个瓶,得分为10 + 下两次投球击倒的瓶数
- 第10轮特殊规则:
- 如果是补中,玩家可以额外投球1次
- 如果是全中,玩家可以额外投球2次
让我们先看看练习提供的结构和函数签名:
#[derive(Debug, PartialEq)]
pub enum Error {
NotEnoughPinsLeft,
GameComplete,
}
pub struct BowlingGame {}
impl BowlingGame {
pub fn new() -> Self {
unimplemented!();
}
pub fn roll(&mut self, pins: u16) -> Result<(), Error> {
unimplemented!("Record that {} pins have been scored", pins);
}
pub fn score(&self) -> Option<u16> {
unimplemented!("Return the score if the game is complete, or None if not.");
}
}
我们需要实现这个结构体,它应该能够:
- 跟踪游戏状态
- 记录每次投球的结果
- 根据规则计算得分
- 处理各种错误情况
算法设计
1. 数据结构设计
#[derive(Debug, PartialEq)]
pub enum Error {
NotEnoughPinsLeft,
GameComplete,
}
#[derive(Debug, Clone)]
enum Frame {
InProgress { rolls: Vec<u16> },
Complete { rolls: Vec<u16> },
}
pub struct BowlingGame {
frames: Vec<Frame>,
current_frame: usize,
}
impl BowlingGame {
pub fn new() -> Self {
let mut frames = Vec::with_capacity(10);
for _ in 0..10 {
frames.push(Frame::InProgress { rolls: Vec::with_capacity(2) });
}
BowlingGame {
frames,
current_frame: 0,
}
}
pub fn roll(&mut self, pins: u16) -> Result<(), Error> {
// 检查游戏是否已完成
if self.is_game_complete() {
return Err(Error::GameComplete);
}
// 检查投球是否有效
if pins > 10 {
return Err(Error::NotEnoughPinsLeft);
}
// 获取当前轮次
let current_frame_index = self.current_frame;
if let Frame::InProgress { rolls } = &mut self.frames[current_frame_index] {
// 检查当前轮次是否还能投球
if current_frame_index < 9 {
// 前9轮的规则
if rolls.is_empty() {
// 第一次投球
if pins <= 10 {
rolls.push(pins);
// 如果是全中,完成本轮
if pins == 10 {
self.frames[current_frame_index] = Frame::Complete { rolls: rolls.clone() };
self.current_frame += 1;
}
} else {
return Err(Error::NotEnoughPinsLeft);
}
} else {
// 第二次投球
if rolls[0] + pins <= 10 {
rolls.push(pins);
self.frames[current_frame_index] = Frame::Complete { rolls: rolls.clone() };
self.current_frame += 1;
} else {
return Err(Error::NotEnoughPinsLeft);
}
}
} else {
// 第10轮的特殊规则
self.handle_tenth_frame(pins, rolls)?;
}
} else {
return Err(Error::GameComplete);
}
Ok(())
}
pub fn score(&self) -> Option<u16> {
// 检查游戏是否已完成
if !self.is_game_complete() {
return None;
}
let mut total_score = 0;
for (i, frame) in self.frames.iter().enumerate() {
if let Frame::Complete { rolls } = frame {
let frame_score = rolls.iter().sum::<u16>();
total_score += frame_score;
// 计算奖励分
if i < 9 { // 前9轮才需要计算奖励
if rolls.len() == 1 && rolls[0] == 10 {
// 全中
total_score += self.strike_bonus(i);
} else if rolls.len() == 2 && rolls[0] + rolls[1] == 10 {
// 补中
total_score += self.spare_bonus(i);
}
}
} else {
// 如果有任何轮次未完成,游戏未结束
return None;
}
}
Some(total_score)
}
fn is_game_complete(&self) -> bool {
if self.current_frame < 9 {
return false;
}
if self.current_frame > 9 {
return true;
}
// 检查第10轮是否完成
matches!(self.frames[9], Frame::Complete { .. })
}
fn strike_bonus(&self, frame_index: usize) -> u16 {
if frame_index >= 9 {
return 0;
}
let next_frame = &self.frames[frame_index + 1];
match next_frame {
Frame::Complete { rolls } => {
if rolls.len() >= 2 {
rolls[0] + rolls[1]
} else if rolls.len() == 1 {
// 下一轮也是全中
let next_next_frame = &self.frames[frame_index + 2];
if let Frame::Complete { rolls: next_next_rolls } = next_next_frame {
if !next_next_rolls.is_empty() {
rolls[0] + next_next_rolls[0]
} else {
0
}
} else {
0
}
} else {
0
}
}
_ => 0,
}
}
fn spare_bonus(&self, frame_index: usize) -> u16 {
if frame_index >= 9 {
return 0;
}
let next_frame = &self.frames[frame_index + 1];
if let Frame::Complete { rolls } = next_frame {
if !rolls.is_empty() {
rolls[0]
} else {
0
}
} else {
0
}
}
fn handle_tenth_frame(&mut self, pins: u16, rolls: &mut Vec<u16>) -> Result<(), Error> {
match rolls.len() {
0 => {
// 第一次投球
rolls.push(pins);
if pins < 10 {
// 不是全中,还可以继续投
Ok(())
} else {
// 全中,还需要投两次
Ok(())
}
}
1 => {
// 第二次投球
if rolls[0] == 10 {
// 第一次是全中
if pins <= 10 {
rolls.push(pins);
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
} else {
// 第一次不是全中
if rolls[0] + pins <= 10 {
rolls.push(pins);
if rolls[0] + pins < 10 {
// 普通完成
self.frames[self.current_frame] = Frame::Complete { rolls: rolls.clone() };
self.current_frame += 1;
Ok(())
} else {
// 补中,还需要再投一次
Ok(())
}
} else {
Err(Error::NotEnoughPinsLeft)
}
}
}
2 => {
// 第三次投球(仅在第10轮可能)
if rolls[0] == 10 && rolls[1] < 10 {
// 第一次全中,第二次不是全中
if rolls[1] + pins <= 10 {
rolls.push(pins);
self.frames[self.current_frame] = Frame::Complete { rolls: rolls.clone() };
self.current_frame += 1;
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
} else if rolls[0] == 10 && rolls[1] == 10 {
// 连续两次全中
if pins <= 10 {
rolls.push(pins);
self.frames[self.current_frame] = Frame::Complete { rolls: rolls.clone() };
self.current_frame += 1;
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
} else if rolls[0] + rolls[1] == 10 {
// 补中
if pins <= 10 {
rolls.push(pins);
self.frames[self.current_frame] = Frame::Complete { rolls: rolls.clone() };
self.current_frame += 1;
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
} else {
Err(Error::GameComplete)
}
}
_ => Err(Error::GameComplete),
}
}
}
简化实现
上面的实现较为复杂,让我们尝试一个更简洁的版本:
#[derive(Debug, PartialEq)]
pub enum Error {
NotEnoughPinsLeft,
GameComplete,
}
pub struct BowlingGame {
rolls: Vec<u16>,
}
impl BowlingGame {
pub fn new() -> Self {
BowlingGame {
rolls: Vec::new(),
}
}
pub fn roll(&mut self, pins: u16) -> Result<(), Error> {
// 检查游戏是否已完成
if self.score().is_some() {
return Err(Error::GameComplete);
}
// 检查投球是否有效
if pins > 10 {
return Err(Error::NotEnoughPinsLeft);
}
// 检查当前投球是否合法
let roll_index = self.rolls.len();
// 检查是否违反每轮的瓶数限制
if roll_index >= 2 {
let frame_index = roll_index / 2;
// 如果不是第10轮且不是额外投球
if frame_index < 9 {
// 如果前一次是全中,则当前是新轮次
let is_strike = roll_index % 2 == 1 && self.rolls[roll_index - 1] == 10;
if !is_strike {
// 检查本轮总瓶数
let current_frame_start = frame_index * 2;
let frame_total = self.rolls[current_frame_start] + pins;
if frame_total > 10 {
return Err(Error::NotEnoughPinsLeft);
}
}
} else if frame_index == 9 {
// 第10轮的特殊规则
self.validate_tenth_frame(roll_index, pins)?;
}
}
self.rolls.push(pins);
Ok(())
}
pub fn score(&self) -> Option<u16> {
if self.rolls.len() < 12 {
// 至少需要12次投球才可能完成游戏(9轮零投球 + 第10轮至少2次投球)
// 但实际可能需要更多,取决于是否是全中或补中
let mut complete_frames = 0;
let mut roll_index = 0;
while complete_frames < 10 && roll_index < self.rolls.len() {
if roll_index + 1 < self.rolls.len() {
if self.rolls[roll_index] == 10 {
// 全中
complete_frames += 1;
roll_index += 1;
} else if self.rolls[roll_index] + self.rolls[roll_index + 1] == 10 {
// 补中
if roll_index + 2 < self.rolls.len() {
complete_frames += 1;
roll_index += 2;
} else {
// 还需要额外投球
return None;
}
} else {
// 普通轮次
complete_frames += 1;
roll_index += 2;
}
} else {
// 只有一次投球记录,游戏未完成
return None;
}
}
if complete_frames < 10 {
return None;
}
}
let mut score = 0;
let mut roll_index = 0;
let mut frame = 0;
while frame < 10 {
if roll_index >= self.rolls.len() {
return None;
}
if self.rolls[roll_index] == 10 {
// 全中
if roll_index + 2 < self.rolls.len() {
score += 10 + self.rolls[roll_index + 1] + self.rolls[roll_index + 2];
roll_index += 1;
} else {
return None;
}
} else if roll_index + 1 < self.rolls.len()
&& self.rolls[roll_index] + self.rolls[roll_index + 1] == 10 {
// 补中
if roll_index + 2 < self.rolls.len() {
score += 10 + self.rolls[roll_index + 2];
roll_index += 2;
} else {
return None;
}
} else if roll_index + 1 < self.rolls.len() {
// 普通轮次
score += self.rolls[roll_index] + self.rolls[roll_index + 1];
roll_index += 2;
} else {
return None;
}
frame += 1;
}
Some(score)
}
fn validate_tenth_frame(&self, roll_index: usize, pins: u16) -> Result<(), Error> {
let rolls_in_tenth = roll_index - 18; // 前9轮18次投球
match rolls_in_tenth {
0 => {
// 第10轮第一次投球,总是合法的
Ok(())
}
1 => {
// 第10轮第二次投球
if self.rolls[18] == 10 {
// 第一次是全中,第二次最多10个瓶
if pins <= 10 {
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
} else {
// 第一次不是全中,两次总和不能超过10
if self.rolls[18] + pins <= 10 {
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
}
}
2 => {
// 第10轮第三次投球
if self.rolls[18] == 10 && self.rolls[19] < 10 {
// 第一次全中,第二次不是全中
if self.rolls[19] + pins <= 10 {
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
} else if self.rolls[18] + self.rolls[19] == 10 {
// 补中
if pins <= 10 {
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
} else if self.rolls[18] == 10 && self.rolls[19] == 10 {
// 连续两次全中
if pins <= 10 {
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
} else {
Err(Error::NotEnoughPinsLeft)
}
}
_ => Err(Error::NotEnoughPinsLeft),
}
}
}
测试用例分析
通过查看测试用例,我们可以更好地理解需求:
#[test]
fn you_cannot_roll_more_than_ten_pins_in_a_single_roll() {
let mut game = BowlingGame::new();
assert_eq!(game.roll(11), Err(Error::NotEnoughPinsLeft));
}
单次投球不能超过10个瓶。
#[test]
fn a_game_score_is_some_if_ten_frames_have_been_rolled() {
let mut game = BowlingGame::new();
for _ in 0..10 {
let _ = game.roll(0);
let _ = game.roll(0);
}
assert!(game.score().is_some());
}
完成10轮后可以计算得分。
#[test]
fn spare_in_the_first_frame_followed_by_zeros() {
let mut game = BowlingGame::new();
let _ = game.roll(6);
let _ = game.roll(4);
for _ in 0..18 {
let _ = game.roll(0);
}
assert_eq!(game.score(), Some(10));
}
补中的得分是10 + 下一次投球得分。
#[test]
fn points_scored_in_the_two_rolls_after_a_strike_are_counted_twice_as_a_bonus() {
let mut game = BowlingGame::new();
let _ = game.roll(10);
let _ = game.roll(5);
let _ = game.roll(3);
for _ in 0..16 {
let _ = game.roll(0);
}
assert_eq!(game.score(), Some(26));
}
全中的得分是10 + 后两次投球得分。
#[test]
fn all_strikes_is_a_perfect_score_of_300() {
let mut game = BowlingGame::new();
for _ in 0..12 {
let _ = game.roll(10);
}
assert_eq!(game.score(), Some(300));
}
完美游戏(12次全中)得分为300分。
完整实现
考虑所有边界情况的完整实现:
#[derive(Debug, PartialEq)]
pub enum Error {
NotEnoughPinsLeft,
GameComplete,
}
pub struct BowlingGame {
rolls: Vec<u16>,
}
impl BowlingGame {
pub fn new() -> Self {
BowlingGame {
rolls: Vec::new(),
}
}
pub fn roll(&mut self, pins: u16) -> Result<(), Error> {
// 检查游戏是否已完成
if self.is_game_complete() {
return Err(Error::GameComplete);
}
// 检查投球是否有效
if pins > 10 {
return Err(Error::NotEnoughPinsLeft);
}
// 检查当前投球是否违反规则
let roll_index = self.rolls.len();
if roll_index >= 2 {
let frame_index = roll_index / 2;
if frame_index < 9 {
// 前9轮
let is_strike = roll_index % 2 == 1 && self.rolls[roll_index - 1] == 10;
if !is_strike {
// 检查本轮总瓶数
let current_frame_start = frame_index * 2;
let frame_total = self.rolls[current_frame_start] + pins;
if frame_total > 10 {
return Err(Error::NotEnoughPinsLeft);
}
}
} else if frame_index == 9 {
// 第10轮特殊规则
self.validate_tenth_frame_roll(pins)?;
}
}
self.rolls.push(pins);
Ok(())
}
pub fn score(&self) -> Option<u16> {
if !self.is_game_complete() {
return None;
}
let mut score = 0;
let mut roll_index = 0;
let mut frame = 0;
while frame < 10 {
if roll_index >= self.rolls.len() {
return None;
}
if self.rolls[roll_index] == 10 {
// 全中
if roll_index + 2 < self.rolls.len() {
score += 10 + self.rolls[roll_index + 1] + self.rolls[roll_index + 2];
roll_index += 1;
} else {
return None;
}
} else if roll_index + 1 < self.rolls.len()
&& self.rolls[roll_index] + self.rolls[roll_index + 1] == 10 {
// 补中
if roll_index + 2 < self.rolls.len() {
score += 10 + self.rolls[roll_index + 2];
roll_index += 2;
} else {
return None;
}
} else if roll_index + 1 < self.rolls.len() {
// 普通轮次
score += self.rolls[roll_index] + self.rolls[roll_index + 1];
roll_index += 2;
} else {
return None;
}
frame += 1;
}
Some(score)
}
fn is_game_complete(&self) -> bool {
let mut complete_frames = 0;
let mut roll_index = 0;
while complete_frames < 10 && roll_index < self.rolls.len() {
if roll_index + 1 < self.rolls.len() {
if self.rolls[roll_index] == 10 {
// 全中
complete_frames += 1;
roll_index += 1;
// 第10轮全中需要额外检查
if complete_frames == 10 && roll_index < self.rolls.len() {
// 需要确保有足够的额外投球
if roll_index + 1 >= self.rolls.len() {
return false;
}
}
} else if self.rolls[roll_index] + self.rolls[roll_index + 1] == 10 {
// 补中
if roll_index + 2 < self.rolls.len() {
complete_frames += 1;
roll_index += 2;
} else {
// 还需要额外投球
return false;
}
} else {
// 普通轮次
complete_frames += 1;
roll_index += 2;
}
} else {
// 只有一次投球记录,游戏未完成
return false;
}
}
complete_frames >= 10
}
fn validate_tenth_frame_roll(&self, pins: u16) -> Result<(), Error> {
let tenth_frame_rolls = &self.rolls[18..]; // 前9轮18次投球
let roll_count = tenth_frame_rolls.len();
match roll_count {
0 => Ok(()), // 第一次投球总是合法
1 => {
// 第二次投球
if tenth_frame_rolls[0] == 10 {
// 第一次是全中
if pins <= 10 {
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
} else {
// 第一次不是全中
if tenth_frame_rolls[0] + pins <= 10 {
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
}
}
2 => {
// 第三次投球
if tenth_frame_rolls[0] == 10 && tenth_frame_rolls[1] < 10 {
// 第一次全中,第二次不是全中
if tenth_frame_rolls[1] + pins <= 10 {
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
} else if tenth_frame_rolls[0] + tenth_frame_rolls[1] == 10 {
// 补中
if pins <= 10 {
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
} else if tenth_frame_rolls[0] == 10 && tenth_frame_rolls[1] == 10 {
// 连续两次全中
if pins <= 10 {
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
} else {
Err(Error::NotEnoughPinsLeft)
}
}
_ => Err(Error::NotEnoughPinsLeft),
}
}
}
错误处理和边界情况
考虑更多边界情况的实现:
#[derive(Debug, PartialEq)]
pub enum Error {
NotEnoughPinsLeft,
GameComplete,
}
pub struct BowlingGame {
rolls: Vec<u16>,
}
impl BowlingGame {
pub fn new() -> Self {
BowlingGame {
rolls: Vec::new(),
}
}
pub fn roll(&mut self, pins: u16) -> Result<(), Error> {
// 检查游戏是否已完成
if self.is_game_complete() {
return Err(Error::GameComplete);
}
// 检查投球是否有效
if pins > 10 {
return Err(Error::NotEnoughPinsLeft);
}
// 检查当前投球是否违反规则
let roll_index = self.rolls.len();
if roll_index >= 2 {
let frame_index = roll_index / 2;
if frame_index < 9 {
// 前9轮
let is_strike = roll_index % 2 == 1 && self.rolls[roll_index - 1] == 10;
if !is_strike {
// 检查本轮总瓶数
let current_frame_start = frame_index * 2;
let frame_total = self.rolls[current_frame_start] + pins;
if frame_total > 10 {
return Err(Error::NotEnoughPinsLeft);
}
}
} else if frame_index == 9 {
// 第10轮特殊规则
self.validate_tenth_frame(roll_index, pins)?;
}
}
self.rolls.push(pins);
Ok(())
}
pub fn score(&self) -> Option<u16> {
if !self.is_game_complete() {
return None;
}
let mut score = 0;
let mut roll_index = 0;
let mut frame = 0;
while frame < 10 {
if roll_index >= self.rolls.len() {
return None;
}
if self.rolls[roll_index] == 10 {
// 全中
if roll_index + 2 < self.rolls.len() {
score += 10 + self.rolls[roll_index + 1] + self.rolls[roll_index + 2];
roll_index += 1;
} else {
return None;
}
} else if roll_index + 1 < self.rolls.len()
&& self.rolls[roll_index] + self.rolls[roll_index + 1] == 10 {
// 补中
if roll_index + 2 < self.rolls.len() {
score += 10 + self.rolls[roll_index + 2];
roll_index += 2;
} else {
return None;
}
} else if roll_index + 1 < self.rolls.len() {
// 普通轮次
score += self.rolls[roll_index] + self.rolls[roll_index + 1];
roll_index += 2;
} else {
return None;
}
frame += 1;
}
Some(score)
}
fn is_game_complete(&self) -> bool {
// 检查是否完成10轮
let mut frames_completed = 0;
let mut i = 0;
while frames_completed < 10 && i < self.rolls.len() {
if i + 1 < self.rolls.len() {
if self.rolls[i] == 10 {
// 全中
frames_completed += 1;
i += 1;
} else if self.rolls[i] + self.rolls[i + 1] == 10 {
// 补中
if i + 2 < self.rolls.len() {
frames_completed += 1;
i += 2;
} else {
return false; // 还需要额外投球
}
} else {
// 普通轮次
frames_completed += 1;
i += 2;
}
} else {
return false; // 投球次数不足
}
}
frames_completed >= 10
}
fn validate_tenth_frame(&self, roll_index: usize, pins: u16) -> Result<(), Error> {
let tenth_frame_start = 18; // 前9轮共18次投球
if roll_index < tenth_frame_start {
return Ok(());
}
let tenth_rolls: &[u16] = &self.rolls[tenth_frame_start..];
let current_roll_in_tenth = roll_index - tenth_frame_start;
match current_roll_in_tenth {
0 => Ok(()), // 第一次投球总是合法
1 => {
// 第二次投球
if tenth_rolls[0] == 10 {
// 第一次是全中
if pins <= 10 {
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
} else {
// 第一次不是全中
if tenth_rolls[0] + pins <= 10 {
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
}
}
2 => {
// 第三次投球
if tenth_rolls.len() < 3 {
return Err(Error::NotEnoughPinsLeft);
}
if tenth_rolls[0] == 10 && tenth_rolls[1] < 10 {
// 第一次全中,第二次不是全中
if tenth_rolls[1] + pins <= 10 {
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
} else if tenth_rolls[0] + tenth_rolls[1] == 10 {
// 补中
if pins <= 10 {
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
} else if tenth_rolls[0] == 10 && tenth_rolls[1] == 10 {
// 连续两次全中
if pins <= 10 {
Ok(())
} else {
Err(Error::NotEnoughPinsLeft)
}
} else {
Err(Error::NotEnoughPinsLeft)
}
}
_ => Err(Error::NotEnoughPinsLeft),
}
}
}
实际应用场景
保龄球计分系统在实际开发中有以下应用:
- 体育应用:保龄球馆的计分系统
- 游戏开发:体育类游戏的计分逻辑
- 状态机实现:复杂业务逻辑的状态管理
- 规则引擎:基于规则的计算系统
算法复杂度分析
-
时间复杂度:
- roll 操作:O(1)
- score 操作:O(n),其中 n 是投球次数(最多21次)
-
空间复杂度:O(n),存储所有投球记录
与其他实现方式的比较
// 使用面向对象的状态模式实现
trait FrameState {
fn roll(&mut self, pins: u16) -> Result<(), Error>;
fn is_complete(&self) -> bool;
fn score(&self) -> u16;
}
struct InProgressFrame {
rolls: Vec<u16>,
}
struct CompleteFrame {
rolls: Vec<u16>,
bonus: u16,
}
// 状态模式实现更加复杂,但对于某些场景可能更清晰
总结
通过 bowling 练习,我们学到了:
- 状态管理:掌握了复杂游戏状态的跟踪和管理
- 规则实现:学会了如何将复杂的业务规则转换为代码
- 错误处理:熟练使用 Result 类型处理各种错误情况
- 边界处理:理解了如何处理各种边界情况和特殊规则
- 算法设计:了解了游戏计分算法的设计思路
- 测试驱动:通过丰富的测试用例确保实现的正确性
这些技能在实际开发中非常有用,特别是在实现复杂业务逻辑、游戏系统和状态管理应用时。保龄球计分虽然看起来简单,但它涉及到了状态机设计、规则实现和复杂逻辑处理等许多核心概念,是学习 Rust 系统设计的良好起点。
通过这个练习,我们也看到了 Rust 在处理复杂状态和错误处理方面的强大能力,以及如何用安全且清晰的方式表达复杂的业务规则。这种结合了安全性和表达力的语言特性正是 Rust 的魅力所在。
19万+

被折叠的 条评论
为什么被折叠?



