Cómo no copiar código en Rust

La primera regla de los buenos modales en la programación (o una de las primeras) es: "No copie el código". Usa funciones y herencia.





Si bien todo está claro con las funciones, la herencia es más complicada. Probablemente sepa que no hay herencia directa en Rust, pero hay formas de lograr algo similar. Te contaré sobre ellos.





rasgo impl dyn

, , required ( , ) provided (, ). ? , - , - next()



. - map()



, filter()



, fold()



.. .





, RPG. , , , , , , , :





enum Damage{
    Physical(f32),
    Magic(f32)
}

trait Character{
  fn get_magic_resistance(&self) -> f32;
  fn get_physical_resistance(&self) -> f32;
  fn set_hp(&mut self, new_value: f32);
  fn get_hp(&self) -> f32;
  fn get_type(&self) -> CharacterType;
  fn get_dmg(&self) -> Damage;
}

impl dyn Character {
  fn make_hurt(&mut self, dmg: Damage) {
    match dmg{
      Damage::Physical(dmg) => self.set_hp(self.get_hp() - dmg / self.get_physical_resistance().exp()),
      Damage::Magic(dmg) => self.set_hp(self.get_hp() - dmg / self.get_magic_resistance().exp())
    }
  }
}

#[derive(Debug, Clone, Copy)]
enum CharacterType {
    Mage,
    Warrior,
    Rogue
}

impl Default for CharacterType {
    fn default() -> Self{
        CharacterType::Warrior
    }
}

#[derive(Default)]
struct Player{
    ty: CharacterType,
    phys_resist: f32,
    mag_resist: f32,
    hp: f32,
    dmg: f32
}

impl Player {
    pub fn new(ty: CharacterType, hp: f32, dmg: f32) -> Self {
        Self{ ty, hp, dmg, .. Default::default() }
    }
}

impl Character for Player{
    #[inline]
    fn get_magic_resistance(&self) -> f32 {
        self.mag_resist
    }
    
    #[inline]
    fn get_physical_resistance(&self) -> f32{
        self.phys_resist
    }
    
    #[inline]
    fn set_hp(&mut self, new_value: f32){
        self.hp = new_value;
    }
    
    #[inline]
    fn get_hp(&self) -> f32 {
        self.hp
    }
    
    #[inline]
    fn get_type(&self) -> CharacterType {
        self.ty
    }
    
    fn get_dmg(&self) -> Damage{
        match self.ty {
            CharacterType::Mage => Damage::Magic(self.dmg),
            _ => Damage::Physical(self.dmg)
        }
    }
}

struct EnemyWarrior{
    ty: CharacterType,
    phys_resist: f32,
    mag_resist: f32,
    hp: f32,
    dmg: f32
}

impl Default for EnemyWarrior {
    fn default() -> Self {
        Self{
            ty: CharacterType::Warrior,
            phys_resist: 0.,
            mag_resist: 0.,
            hp: 10.,
            dmg: 1.
        }
    }
}

impl Character for EnemyWarrior{
    #[inline]
    fn get_magic_resistance(&self) -> f32 {
        self.mag_resist
    }
    
    #[inline]
    fn get_physical_resistance(&self) -> f32{
        self.phys_resist
    }
    
    #[inline]
    fn set_hp(&mut self, new_value: f32){
        self.hp = new_value;
    }
    
    #[inline]
    fn get_hp(&self) -> f32 {
        self.hp
    }
    
    fn get_type(&self) -> CharacterType {
        CharacterType::Warrior
    }
    
    fn get_dmg(&self) -> Damage{
        match self.ty {
            CharacterType::Mage => Damage::Magic(self.dmg),
            _ => Damage::Physical(self.dmg)
        }
    }
}

fn main(){
    let mut player = Player::new(CharacterType::Warrior, 10., 1.);
    let mut enemy = EnemyWarrior::default();
    
    <dyn Character>::make_hurt(&mut enemy, player.get_dmg());
    println!("{}", enemy.get_hp());
}
      
      



TL;DR 2 Character, 6 required 1 provided .





: " ?" , - , , required . -, , 6, , , - . , , - ?





Deref<Target=_>

Deref. , , , , , image : ImageBuffer Deref [P::Subpixel] , , , . Deref , .





use std::ops::Deref;
use std::ops::DerefMut;

enum Damage{
    Physical(f32),
    Magic(f32)
}

#[derive(Default)]
struct Character{
    ty: CharacterType,
    phys_resist: f32,
    mag_resist: f32,
    hp: f32,
    dmg: f32
}

impl Character {
    #[inline]
    fn get_magic_resistance(&self) -> f32 {
        self.mag_resist
    }
    
    #[inline]
    fn get_physical_resistance(&self) -> f32{
        self.phys_resist
    }
    
    #[inline]
    fn set_hp(&mut self, new_value: f32){
        self.hp = new_value;
    }
    
    #[inline]
    fn get_hp(&self) -> f32 {
        self.hp
    }
    
    #[inline]
    fn get_type(&self) -> CharacterType {
        self.ty
    }
    
    fn get_dmg(&self) -> Damage{
        match self.ty {
            CharacterType::Mage => Damage::Magic(self.dmg),
            _ => Damage::Physical(self.dmg)
        }
    }

  fn make_hurt(&mut self, dmg: Damage) {
    match dmg{
      Damage::Physical(dmg) => self.set_hp(self.get_hp() - dmg / self.get_physical_resistance().exp()),
      Damage::Magic(dmg) => self.set_hp(self.get_hp() - dmg / self.get_magic_resistance().exp())
    }
  }
}


#[derive(Debug, Clone, Copy)]
enum CharacterType {
    Mage,
    Warrior,
    Rogue
}

impl Default for CharacterType {
    fn default() -> Self{
        CharacterType::Warrior
    }
}

#[derive(Default)]
struct Player(Character);

impl Player {
    pub fn new(ty: CharacterType, hp: f32, dmg: f32) -> Self {
        Self(Character{ ty, hp, dmg, .. Default::default() })
    }
}

impl Deref for Player {
    type Target = Character;
    
    #[inline]
    fn deref(&self) -> &Self::Target{
        &self.0
    }
}

impl DerefMut for Player {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target{
        &mut self.0
    }
}


struct EnemyWarrior(Character);

impl Default for EnemyWarrior {
    fn default() -> Self {
        Self(Character {
            ty: CharacterType::Warrior,
            phys_resist: 0.,
            mag_resist: 0.,
            hp: 10.,
            dmg: 1.
        })
    }
}

impl Deref for EnemyWarrior {
    type Target = Character;
    
    #[inline]
    fn deref(&self) -> &Self::Target{
        &self.0
    }
}

impl DerefMut for EnemyWarrior {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target{
        &mut self.0
    }
}

fn main(){
    let mut player = Player::new(CharacterType::Warrior, 10., 1.);
    let mut enemy = EnemyWarrior::default();
    
    enemy.make_hurt(player.get_dmg());
    println!("{}", enemy.get_hp());
}
      
      



, . , , , , , , , "", "".





. , "", , , "", . :





struct Child (Parent, ChildInner);

impl Child {
  pub fn get_some_field_from_inner(&self) -> &ChildInner::Field {
    &self.1.field
  }
}
      
      



, , . , , / .





, . -, , , (, , ). Rust, , - , - . Deref, DerefMut , . , , . , self.1, . , , .





Eso es, de hecho, todo lo que quería decir sobre este tema. ¿Me estoy perdiendo de algo? Escribe en los comentarios si también te preocupa este tema, quiero saber que no soy el único que carece de herencia en Rust.








All Articles