Rust中为带关联类型的Pokemon trait实现者实现Battle trait的咨询
解决方案
第一步:补全基础约束与属性定义
首先给Pokemon trait的关联类型Move增加PartialEq约束解决无法对比招式的问题,同时新增属性获取方法用于克制判断:
// 先定义属性枚举用于克制关系判断 #[derive(PartialEq, Clone, Copy)] enum PokemonType { Fire, Water, Grass, } // 属性克制判断逻辑 fn is_effective(attacker: PokemonType, defender: PokemonType) -> bool { match (attacker, defender) { (PokemonType::Fire, PokemonType::Grass) => true, (PokemonType::Water, PokemonType::Fire) => true, (PokemonType::Grass, PokemonType::Water) => true, _ => false, } } // 修正后的Pokemon trait trait Pokemon { // 加PartialEq支持招式对比,加Ord支持招式威力排序 type Move: PartialEq + Ord; fn pick_move(&self) -> Self::Move; // 新增获取宝可梦属性的方法 fn get_type(&self) -> PokemonType; // 新增获取招式威力的方法,统一不同类型招式的对比逻辑 fn move_power(&self) -> u32; }
第二步:为原有属性实现补充方法
给已有的Fire、Water类型补充get_type和move_power实现:
impl Pokemon for Fire { type Move = FireMove; fn pick_move(&self) -> Self::Move { match self { Self::Charmander => Self::Move::Ember, Self::Charmeleon => Self::Move::FlameThrower, Self::Charizard => Self::Move::FireBlast, } } fn get_type(&self) -> PokemonType { PokemonType::Fire } fn move_power(&self) -> u32 { match self.pick_move() { FireMove::Ember => 40, FireMove::FlameThrower => 90, FireMove::FireBlast => 110, } } } // Water类型同理补充 impl Pokemon for Water { type Move = WaterMove; fn pick_move(&self) -> Self::Move { if *self == Water::Squirtle { return Self::Move::Bubble; } Self::Move::WaterGun } fn get_type(&self) -> PokemonType { PokemonType::Water } fn move_power(&self) -> u32 { match self.pick_move() { WaterMove::Bubble => 40, WaterMove::WaterGun => 60, } } }
第三步:统一跨类型宝可梦的包装
由于不同属性的宝可梦是不同的静态类型,要支持跨属性对战需要用枚举统一包装所有宝可梦类型:
#[derive(PartialEq, Clone, Copy)] enum PokemonInstance { Fire(Fire), Water(Water), Grass(Grass), } // 给统一包装类型实现Pokemon trait impl Pokemon for PokemonInstance { type Move = u32; fn pick_move(&self) -> Self::Move { self.move_power() } fn get_type(&self) -> PokemonType { match self { PokemonInstance::Fire(_) => PokemonType::Fire, PokemonInstance::Water(_) => PokemonType::Water, PokemonInstance::Grass(_) => PokemonType::Grass, } } fn move_power(&self) -> u32 { match self { PokemonInstance::Fire(f) => f.move_power(), PokemonInstance::Water(w) => w.move_power(), PokemonInstance::Grass(g) => g.move_power(), } } }
第四步:实现Battle trait
直接为所有满足约束的Pokemon实现Battle trait,同时支持同属性和跨属性对战:
trait Battle: Pokemon + Clone + Copy { fn battle(&self, foe: Self) -> Self { let my_type = self.get_type(); let foe_type = foe.get_type(); let my_power = self.move_power(); let foe_power = foe.move_power(); // 优先判断属性克制 let my_effective = is_effective(my_type, foe_type); let foe_effective = is_effective(foe_type, my_type); match (my_effective, foe_effective) { (true, false) => return *self, (false, true) => return foe, _ => {} } // 克制关系相同的情况下比较招式威力 if my_power >= foe_power { *self } else { foe } } } // 为所有满足约束的Pokemon实现Battle trait impl<T: Pokemon + Clone + Copy> Battle for T {}
使用示例
fn main() { // 同属性对战 let charmander = Fire::Charmander; let charizard = Fire::Charizard; let winner1 = charmander.battle(charizard); assert!(matches!(winner1, Fire::Charizard)); // 跨属性对战 let charizard_inst = PokemonInstance::Fire(Fire::Charizard); let blastoise_inst = PokemonInstance::Water(Water::Blastoise); // 水克制火,所以水属性获胜 let winner2 = charizard_inst.battle(blastoise_inst); assert!(matches!(winner2, PokemonInstance::Water(_))); }
内容的提问来源于stack exchange,提问作者Wave Metric
相关产品推荐
相关产品推荐

