Chapter 11 - Interfaces
Exercise 1: Interfaces
Here we have Cuboid and Sphere types, both of which have Volume and SurfaceArea methods. We also have a PrintInfo function that accepts a Cuboid, and calls Volume and SurfaceArea on it so it can print that info.
In the main function we pass a Cuboid to PrintInfo, which compiles fine. But then we try to pass a Sphere to PrintInfo as well, which results in a compile error. PrintInfo is only set up to accept Cuboid values, even though Sphere values have identical methods.
Let’s get the PrintInfo function to accept both Cuboid and Sphere values. Define a Solid interface consisting of Volume and SurfaceArea methods. Then modify PrintInfo to accept a parameter with a Solid interface type instead of Cuboid.
package main
import (
"fmt"
"math"
)
type Cuboid struct {
width float64
length float64
height float64
}
func (c Cuboid) Volume() float64 {
return c.length * c.width * c.height
}
func (c Cuboid) SurfaceArea() float64 {
area := 2 * c.length * c.width
area += 2 * c.length * c.height
area += 2 * c.height * c.width
return area
}
type Sphere struct {
radius float64
}
func (s Sphere) Volume() float64 {
return (4.0 / 3.0) * math.Pi * math.Pow(s.radius, 3)
}
func (s Sphere) SurfaceArea() float64 {
return 2 * math.Pi * math.Pow(s.radius, 2)
}
// YOUR CODE HERE: Define a Solid interface.
// YOUR CODE HERE: Revise PrintInfo to accept a parameter
// that satisfies the Solid interface.
func PrintInfo(c Cuboid) {
fmt.Println(c)
fmt.Printf("Volume: %0.3f\n", c.Volume())
fmt.Printf("Surface Area: %0.3f\n", c.SurfaceArea())
}
func main() {
c := Cuboid{length: 2.5, width: 5.0, height: 10.5}
PrintInfo(c)
s := Sphere{radius: 2.0}
PrintInfo(s)
}Compile Error:
./prog.go:47:11: cannot use s (type Sphere) as type Cuboid in argument to PrintInfo
When you’re ready, have a look at our solution.
Exercise 2: Type Assertions
Here are updated Fan and CoffeePot types, both of which satisfy an Appliance interface. We’ve also added a Use method that accepts an Appliance. Currently, Use only calls the TurnOn method on the Appliance…
Update Use so that it calls Oscillate on the Appliance if (and only if) it’s a Fan. Use should also call Brew on the Appliance if (and only if) it’s a CoffeePot.
package main
import "fmt"
type Appliance interface {
TurnOn()
}
type Fan string
func (f Fan) TurnOn() {
fmt.Println("Spinning")
}
func (f Fan) Oscillate() {
fmt.Println("Rotating on base")
}
type CoffeePot string
func (c CoffeePot) TurnOn() {
fmt.Println("Powering up")
}
func (c CoffeePot) Brew() {
fmt.Println("Heating Up")
}
func Use(appliance Appliance) {
fmt.Println(appliance)
appliance.TurnOn()
// YOUR CODE HERE: If the appliance is a
// Fan, call its Oscillate method.
// If the appliance is a CoffeePot, call
// its Brew method.
}
func main() {
Use(Fan("Windco Breeze"))
Use(CoffeePot("LuxBrew"))
}Desired Output:
Windco Breeze
Spinning
Rotating on base
LuxBrew
Powering up
Heating Up
Here’s our solution.