How not to copy code in Rust

The first rule of good manners in programming (or one of the first) is: "Don't copy the code." Use functions and inheritance.





While everything is clear with functions, inheritance is more complicated. You probably know that there is no direct inheritance in Rust, but there are ways to achieve something similar to it. I'll tell you about them.





impl dyn Trait

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





That is, in fact, all that I wanted to say on this topic. Am I missing something? Write in the comments if you are also concerned about this topic, I want to know that I'm not the only one who lacks inheritance in Rust.








All Articles