Rust中如何获取枚举变体Move的Symbol参数?
问题描述
现有如下枚举定义:
pub enum Symbol { X, O, } pub enum CellContent { Move(Symbol), Empty, }
变量实例:
let cell_content = CellContent::Move(Symbol::X);
需求:判断变量是否为CellContent::Move(Symbol)变体,若是则返回Symbol的副本;若否则不执行操作,继续后续代码检查。
尝试过两种写法均无法正常工作:
第一种写法:
if cell_0_0 == Move(a_symbol) { return Some(a_symbol); }
第二种写法会直接返回导致后续代码无法执行,且编译失败:
match cell_0_0 { Move(symbol) => return symbol; _ => // do nothing; } // code must go on to check further conditions
附完整不工作代码:
pub fn some_one_win(&self) -> Option<Symbol> { let cell_0_0: CellContent = self.table[0][0]; let cell_0_1: CellContent = self.table[0][1]; let cell_0_2: CellContent = self.table[0][2]; if cell_0_0 == cell_0_1 && cell_0_0 == cell_0_2 { match cell_0_0 { Move(symbol) => return symbol; _ => // how to 'do nothing' here ?; } } let cell_1_0: CellContent = self.table[1][0]; let cell_1_1: CellContent = self.table[1][1]; let cell_1_2: CellContent = self.table[1][2]; if cell_1_0 == cell_1_1 && cell_1_0 == cell_1_2 { match cell_1_0 { Move(symbol) => return symbol; _ => // how to 'do nothing' here ?; } } ... and so on .. }
解决方案
1. 先补全枚举的必要 trait
第一种写法编译失败的核心原因是:你定义的Symbol和CellContent没有实现PartialEq(用于相等判断)和Clone(用于返回副本)。给枚举加上派生宏即可:
#[derive(PartialEq, Clone)] pub enum Symbol { X, O, } #[derive(PartialEq, Clone)] pub enum CellContent { Move(Symbol), Empty, }
2. 调整分支逻辑,解决编译错误与提前返回问题
原第二种写法有两个问题:
- 返回值类型不匹配:函数返回
Option<Symbol>,但你直接返回symbol(Symbol类型),必须返回Some(symbol) - 空分支语法错误:Rust不允许空代码块,
_ => {}才是合法的空操作
要保留后续代码执行的逻辑,只需在匹配到Move变体时才返回,其余情况跳过即可。用match的写法如下:
if cell_0_0 == cell_0_1 && cell_0_0 == cell_0_2 { match cell_0_0 { CellContent::Move(symbol) => return Some(symbol.clone()), CellContent::Empty => {} // 空操作,继续执行后续代码 } }
3. 更简洁的if let写法
如果觉得match繁琐,用if let可以直接匹配目标变体,代码更简洁:
if cell_0_0 == cell_0_1 && cell_0_0 == cell_0_2 { if let CellContent::Move(symbol) = cell_0_0 { return Some(symbol.clone()); } // 匹配到Empty时自动跳过,继续执行后续检查 }
4. 完整修正后的代码
统一调整所有检查逻辑后的完整函数示例:
#[derive(PartialEq, Clone)] pub enum Symbol { X, O, } #[derive(PartialEq, Clone)] pub enum CellContent { Move(Symbol), Empty, } pub struct TicTacToe { table: [[CellContent; 3]; 3], } impl TicTacToe { pub fn some_one_win(&self) -> Option<Symbol> { // 检查第一行 let (cell_0_0, cell_0_1, cell_0_2) = (&self.table[0][0], &self.table[0][1], &self.table[0][2]); if cell_0_0 == cell_0_1 && cell_0_0 == cell_0_2 { if let CellContent::Move(symbol) = cell_0_0 { return Some(symbol.clone()); } } // 检查第二行 let (cell_1_0, cell_1_1, cell_1_2) = (&self.table[1][0], &self.table[1][1], &self.table[1][2]); if cell_1_0 == cell_1_1 && cell_1_0 == cell_1_2 { if let CellContent::Move(symbol) = cell_1_0 { return Some(symbol.clone()); } } // 检查第三行、三列、两条对角线的逻辑同理... // 所有情况都不满足,返回None None } }
关键细节说明
- 使用引用
&获取单元格内容,避免不必要的所有权转移,同时PartialEq对引用也能正常工作 - 仅当三个单元格相等且为
Move变体时才返回获胜符号;如果是三个Empty,则跳过继续检查 - 所有检查逻辑执行完毕后,若未找到获胜者,返回
None
内容的提问来源于stack exchange,提问作者realtebo
相关产品推荐
相关产品推荐

