Go Interfaces

Question Click to View Answer

What does the following code print to the console?

package main

import "fmt"

type Greet interface {
    hi() string
}

type Person struct {
    name string
}

func (p Person) hi() string {
    return "hello, I am a person"
}

func printGreeting(g Greet) {
    fmt.Println(g.hi())
}

func main() {
    roy := Person{"roy"}
    printGreeting(roy)
}

hello, I am a person is printed to the console.

A Person struct with a hi() method is defined. A Greet interface is also defined.

You can "implement an interface" by implementing all of the methods on an interface.

Greet only includes hi() in the "method set".

Types need to define a hi() method to implement the Greet interface.

Person defines a hi() method, so it satisfies the requirements of the Greet interface (i.e. it implements all of the methods listed in the Greet method set).

The printGreeting() method takes a Greet type as the argument. This makes printGreeting() more generic than if we had simply defined it for the Person type. printGreeting() can be used by the Person type, but also by any other type that implements the Greet interface.

What does the following code print to the console?

type Greet interface {
    hi() string
    bye() string
}

type Person struct {
    name string
}

func (p Person) hi() string {
    return "hello, I am a person"
}

func printGreeting(g Greet) {
    fmt.Println(g.hi())
}

func main() {
    roy := Person{"roy"}
    printGreeting(roy)
}

The following error is printed:

# command-line-arguments
cannot use roy (type Person) as type Greet in argument to printGreeting:
    Person does not implement Greet (missing bye method)

Greet's method set has been updated to include the hi() and bye() methods.

Person does not implement the Greet interface anymore. This code will work if we add the following method:

func (p Person) bye() string {
    return "goodbye"
}

What does the following code print?

type MathHelper interface {
    count() int
}

type Calculator struct {
    model string
}

func (c Calculator) count() string {
    return "Counting is fun!"
}

func countStuff(m MathHelper) {
    fmt.Println(m.count())
}

func main() {
    myCalculator := Calculator{"the pink one"}
    countStuff(myCalculator)
}
# command-line-arguments
cannot use myCalculator (type Calculator) as type MathHelper in argument to countStuff:
    Calculator does not implement MathHelper (wrong type for count method)
        have count() string
        want count() int

MathHelper requires a count() method that returns an int. Calculator has a count() method that returns a string.

Calculator does not implement the MathHelper interface, so the code errors out.

This change will fix the error:

func (c Calculator) count() int {
    return 10
}

What does the following code print?

type Animal interface {
    sayHi() string
}

type Pokemon struct {
    species string
}

type Dog struct {
    species string
}

func (p Pokemon) sayHi() string {
    return "I am a pokemon"
}

func (d Dog) sayHi() string {
    return "I am a dog"
}

func printHi(a Animal) {
    fmt.Println(a.sayHi())
}

func main() {
    pika := Pokemon{"pika"}
    fido := Dog{"lab"}
    printHi(pika)
    printHi(fido)
}
I am a pokemon
I am a dog

The Animal interface requires a sayHi method that returns a string. Pokemon and Dog both implement the Animal interface.

The printHi function can be used with pika and fido arguments.

We could have also printed ran the sayHi method on all the animals with this code:

func main() {
    pika := Pokemon{"pika"}
    fido := Dog{"lab"}
    animals := []Animal{
        pika,
        fido,
    }
    for _, animal := range animals {
        printHi(animal)
    }
}

Use the following code to write a totalPerimeter method that takes a slice of shapes and calculates the total perimeter of all of the shapes in the slice. Create a rectangle and a circle and verify the totalPerimeter method works as expected.

package main

import "fmt"
import "math"

type Shape interface {
    perimeter() float64
}

type Rectangle struct {
    width, height float64
}

type Circle struct {
    radius float64
}

func (r Rectangle) perimeter() float64 {
    return 2*r.width + 2*r.height
}

func (c Circle) perimeter() float64 {
    return 2 * math.Pi * c.radius
}
func totalPerimeter(shapes []Shape) float64 {
    total := 0.0
    for _, shape := range shapes {
        total += shape.perimeter()
    }
    return total
}

func main() {
    r := Rectangle{width: 3, height: 4}
    c := Circle{radius: 5}
    shapes := []Shape{r, c}
    fmt.Println(totalPerimeter(shapes))
}