簡體   English   中英

在 Rust 中通過關聯類型實現一個 trait 的問題

[英]Problem with implementing a trait over another trait with associated types in Rust

我有這個特點:


trait Pokemon {
    type Move;
    fn pick_move(&self) -> Self::Move;
}

某些類型實現了 trait,如下所示:


#[derive(PartialEq, Clone, Copy)]
enum Fire {
    Charmander,
    Charmeleon,
    Charizard
}

#[derive(PartialEq, Clone, Copy)]
enum FireMove {
    Ember, FlameThrower, FireBlast
}

#[derive(PartialEq, Clone, Copy)]
enum Water {
    Squirtle,
    Wartortle,
    Blastoise
}

#[derive(PartialEq, Clone, Copy)]
enum WaterMove {
    Bubble,
    WaterGun
}

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,
        }
    }
}

impl Pokemon for Water {
    type Move = WaterMove;

    fn pick_move(&self) -> Self::Move {
        if *self == Water::Squirtle {
            return Self::Move::Bubble;
        }
        Self::Move::WaterGun
    }
}

對於實現Pokemon trait 的類型,我想實現一個 trait Battle


trait Battle {
  fn battle(&self) -> ??;
}

最后,我想要實現的是我應該能夠在任何實現Pokemon特性的類型上調用.battle並最終能夠返回贏得戰斗的 Pokemon。

我也考慮過使用這樣的方法:


fn battle<T>(pokemon: T, foe: T) -> T
where T: Pokemon
{
    let p_move = pokemon.pick_move();
    let f_move = foe.pick_move();

    if p_move == f_move {
        return pokemon;
    }

    foe
}

不幸的是,在這里我無法比較已傳遞參數的Move

我接近實現這一目標的一種方法是做這樣的事情:


trait Battle {
    type Pokemons;
    
    fn battle(&self, foe: Self::Pokemons) -> Self::Pokemons;
}

#[derive(PartialEq, Clone, Copy)]
enum PokemonTypes {
    Fire(Fire),
    Water(Water),
    Grass(Grass)
}

impl Battle for Fire {
    type Pokemons = PokemonTypes;

    fn battle(&self, foe: Self::Pokemons) -> Self::Pokemons {
        match foe {
            Self::Pokemons::Water(pokemon) => Self::Pokemons::Water(pokemon),
            _ => Self::Pokemons::Fire(*self) // because Fire beats Grass type
        }
    }
}

所以基本上,我如何實現這個Battle特性來幫助我比較動作和/或口袋妖怪類型並決定獲勝者?

您可以將移動類型抽象為另一個枚舉,並刪除特征中的關聯類型:

#[derive(PartialEq, Clone, Copy)]
enum Move {
    Water(WaterMove),
    Fire(FireMove),
}

trait Pokemon {
    fn pick_move(&self) -> Move;
}

然后以同樣的方式,您可以直接使用Battle系統的實現,通過PokemonType實現對戰:

#[derive(PartialEq, Clone, Copy)]
enum PokemonType {
    Fire(Fire),
    Water(Water),
}

trait Battle {
    fn battle(&self, foe: PokemonType) -> PokemonType;
}

impl Battle for PokemonType {
    fn battle(&self, foe: PokemonType) -> PokemonType {
        match (self, foe) {
            (p1@PokemonType::Water(_), p2@PokemonType::Fire(_)) => {
                *p1
                // do watever
            }
            _ => foe // handle other patterns
        }
    }
}

操場

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM