Search code examples
rusttraits

How to implement a generic data type to another struct's method?


I have this code:

#[derive(Debug)]
pub struct Counter {
    pub calories: f64,
}

pub struct Protein {
    pub weight_in_kg: f64,
}

pub struct Fat {
    pub weight_in_kg: f64,
}

impl Counter {
    fn eat(&mut self, food: T) {
        self.calories += food.gives();
    }
}

pub trait Food {
    fn gives(&self) -> f64;
}

impl Food for Protein {
    fn gives(&self) -> f64 {
        self.weight_in_kg * 4.0
    }
}

impl Food for Fat {
    fn gives(&self) -> f64 {
        self.weight_in_kg * 9.0
    }
}

Which gives this error:

fn eat(&mut self, food: T) { ^ not found in this scope

T can either be Protein or Fat. But I am not sure where to implement T to get it working.


Solution

  • You need to make eat a generic, like this:

    impl Counter {
        // This means make a copy of this method for every used value of `T`
        // Use :Food to make sure `T` can only be food
        fn eat<T: Food>(&mut self, food: T) {
            self.calories += food.gives();
        }
    }
    

    Alternatively:

    impl Counter {
        // This method is often used if you need more complex trait bounds.
        fn eat<T>(&mut self, food: T)
            where T: Food
        {
            self.calories += food.gives();
        }
    }
    

    You can also make the entire struct a generic, in that case each counter can eat only one kind of food.