In this episode we present traits. They are used to define interfaces, which is useful for type-checked template code and for dynamic dispatch. In this way, traits are similar to inheritance in C++ as well as to concepts.
trait Animal {
fn make_noise(&mut self);
fn eat(&mut self, how_much: i64);
fn is_hungry(&self) -> bool;
}
#[derive(Debug)]
struct Dog {
need_food: i64,
}
impl Animal for Dog {
fn make_noise(&mut self) {
println!("Bark!");
self.need_food += 2;
}
fn is_hungry(&self) -> bool {
self.need_food > 0
}
fn eat(&mut self, how_much: i64) {
println!("Dog eating {}", how_much);
self.need_food -= how_much;
}
}
impl Dog {
fn new() -> Dog {
Dog { need_food: 0 }
}
}
#[derive(Debug)]
struct Cat {
need_food: i64,
}
impl Animal for Cat {
fn make_noise(&mut self) {
println!("Meow!");
self.need_food += 1;
}
fn is_hungry(&self) -> bool {
self.need_food > 0
}
fn eat(&mut self, how_much: i64) {
println!("Cat eating {}", how_much);
self.need_food -= how_much;
}
}
impl Cat {
fn new() -> Cat {
Cat { need_food: 0 }
}
}
fn live(mut a: impl Animal) {
//fn live<T:Animal>(mut a : T) {
a.make_noise();
while a.is_hungry() {
a.eat(1);
}
a.make_noise();
}
fn main() {
let d = Dog::new();
live(d);
let c = Cat::new();
live(c);
}
trait Animal {
fn make_noise(&mut self);
fn eat(&mut self, how_much: i64);
fn is_hungry(&self) -> bool;
}
#[derive(Debug)]
struct Dog {
need_food: i64,
}
impl Animal for Dog {
fn make_noise(&mut self) {
println!("Bark!");
self.need_food += 2;
}
fn is_hungry(&self) -> bool {
self.need_food > 0
}
fn eat(&mut self, how_much: i64) {
println!("Dog eating {}", how_much);
self.need_food -= how_much;
}
}
impl Dog {
fn new() -> Dog {
Dog { need_food: 0 }
}
}
#[derive(Debug)]
struct Cat {
need_food: i64,
}
impl Animal for Cat {
fn make_noise(&mut self) {
println!("Meow!");
self.need_food += 1;
}
fn is_hungry(&self) -> bool {
self.need_food > 0
}
fn eat(&mut self, how_much: i64) {
println!("Cat eating {}", how_much);
self.need_food -= how_much;
}
}
impl Cat {
fn new() -> Cat {
Cat { need_food: 0 }
}
}
fn live(mut a: impl Animal) {
//fn live<T:Animal>(mut a : T) {
a.make_noise();
while a.is_hungry() {
a.eat(1);
}
a.make_noise();
}
//fn party(a : &mut impl Animal, b : &mut impl Animal) {
//fn party<T : Animal>(a : &mut T, b : &mut T) { // wrong!
//fn party<T : Animal, U : Animal>(a : &mut T, b : &mut U) {
fn party<T, U>(a: &mut T, b: &mut U)
where
T: Animal,
U: Animal,
{
a.make_noise();
b.make_noise();
while a.is_hungry() {
a.eat(1);
}
while b.is_hungry() {
b.eat(1);
}
b.make_noise();
a.make_noise();
}
fn main() {
{
let d = Dog::new();
live(d);
let c = Cat::new();
live(c);
}
{
let mut d = Dog::new();
let mut c = Cat::new();
party(&mut d, &mut c);
}
}
trait Animal {
fn make_noise(&mut self);
fn eat(&mut self, how_much: i64);
fn is_hungry(&self) -> bool;
}
#[derive(Debug)]
struct Dog {
need_food: i64,
}
impl Animal for Dog {
fn make_noise(&mut self) {
println!("Bark!");
self.need_food += 2;
}
fn is_hungry(&self) -> bool {
self.need_food > 0
}
fn eat(&mut self, how_much: i64) {
println!("Dog eating {}", how_much);
self.need_food -= how_much;
}
}
impl Dog {
fn new() -> Dog {
Dog { need_food: 0 }
}
}
#[derive(Debug)]
struct Cat {
need_food: i64,
}
impl Animal for Cat {
fn make_noise(&mut self) {
println!("Meow!");
self.need_food += 1;
}
fn is_hungry(&self) -> bool {
self.need_food > 0
}
fn eat(&mut self, how_much: i64) {
println!("Cat eating {}", how_much);
self.need_food -= how_much;
}
}
impl Cat {
fn new() -> Cat {
Cat { need_food: 0 }
}
}
fn live(mut a: Box<dyn Animal>) {
a.make_noise();
while a.is_hungry() {
a.eat(1);
}
a.make_noise();
}
fn main() {
let args : Vec<String> = std::env::args().collect();
let a : Box<dyn Animal>;
if args.len() < 2 {
eprintln!("Usage: DOG or CAT as argument");
return;
}
if args[1] == "CAT" {
a = Box::new(Cat::new());
} else if args[1] == "DOG" {
a = Box::new(Dog::new());
} else {
eprintln!("Need DOG or CAT argument!");
return;
}
live(a);
}
trait Animal {
fn make_noise(&mut self);
fn eat(&mut self, how_much: i64);
fn is_hungry(&self) -> bool;
}
#[derive(Debug)]
struct Dog {
need_food: i64,
}
impl Animal for Dog {
fn make_noise(&mut self) {
println!("Bark!");
self.need_food += 2;
}
fn is_hungry(&self) -> bool {
self.need_food > 0
}
fn eat(&mut self, how_much: i64) {
println!("Dog eating {}", how_much);
self.need_food -= how_much;
}
}
impl Dog {
fn new() -> Dog {
Dog { need_food: 0 }
}
}
#[derive(Debug)]
struct Cat {
need_food: i64,
}
impl Animal for Cat {
fn make_noise(&mut self) {
println!("Meow!");
self.need_food += 1;
}
fn is_hungry(&self) -> bool {
self.need_food > 0
}
fn eat(&mut self, how_much: i64) {
println!("Cat eating {}", how_much);
self.need_food -= how_much;
}
}
impl Cat {
fn new() -> Cat {
Cat { need_food: 0 }
}
}
fn live(mut a: Box<dyn Animal>) -> Box<dyn Animal> {
a.make_noise();
while a.is_hungry() {
a.eat(1);
}
a.make_noise();
a
}
fn main() {
let args : Vec<String> = std::env::args().collect();
let a : Box<dyn Animal>;
if args.len() < 2 {
eprintln!("Usage: DOG or CAT as argument");
return;
}
if args[1] == "CAT" {
a = Box::new(Cat::new());
} else if args[1] == "DOG" {
a = Box::new(Dog::new());
} else {
eprintln!("Need DOG or CAT argument!");
return;
}
let mut b = live(a);
b.make_noise();
}