package main import ( "fmt" "reflect" ) // Animal base "class". type Animal struct { Name string mean bool } // AnimalSounder interface exposes MakeNoise() method, which provides the different Animal "sounds". type AnimalSounder interface { MakeNoise() } // Dog is a type of Animal. type Dog struct { Animal BarkStrength int } // Cat is a type of Animal. type Cat struct { Basics Animal MeowStrength int } // Lion is a type of Animal. type Lion struct { Basics Animal RoarStrength int } // MakeNoise (*Dog) barks. func (animal *Dog) MakeNoise() { animalType := reflect.ValueOf(animal).Type().Elem().Name() animal.PerformNoise(animal.BarkStrength, "BARK", animalType) } // MakeNoise (*Cat) meows. func (animal *Cat) MakeNoise() { animalType := reflect.ValueOf(animal).Type().Elem().Name() animal.Basics.PerformNoise(animal.MeowStrength, "MEOW", animalType) } // MakeNoise (*Lion) roars. func (animal *Lion) MakeNoise() { animalType := reflect.ValueOf(animal).Type().Elem().Name() animal.Basics.PerformNoise(animal.RoarStrength, "ROAR!! ", animalType) } // MakeSomeNoise exposes AnimalSounder's MakeNoise() method. func MakeSomeNoise(animalSounder AnimalSounder) { animalSounder.MakeNoise() } func main() { myDog := &Dog{ Animal{ Name: "Rover", // Name mean: false, // mean }, 2, // BarkStrength } myCat := &Cat{ Basics: Animal{ Name: "Julius", mean: true, }, MeowStrength: 3, } wildLion := &Lion{ Basics: Animal{ Name: "Aslan", mean: true, }, RoarStrength: 5, } MakeSomeNoise(myDog) MakeSomeNoise(myCat) MakeSomeNoise(wildLion) } // PerformNoise is a generic method shared by all implementations of Animal. func (animal *Animal) PerformNoise(strength int, sound string, animalType string) { if animal.mean == true { strength = strength * 5 } fmt.Printf("%s (%s): \n", animal.Name, animalType) for voice := 0; voice < strength; voice++ { fmt.Printf("%s ", sound) } fmt.Println("\n") }