loading...

Continue - Empty Interfaces in Go

shearywtan profile image Sheary Tan ・3 min read

Empty interface

As the name stated, it does not contain any methods. This is useful when we want to store different types of data.

From the previous post, we only use numbers for our example. What if we want to include different types of data?

For example:

package main

import "fmt"

type animal struct {
    age   int
    color string
    sound string
}

type cat struct {
    animal
    bossy bool
}

type dog struct {
    animal
    friendly bool
}

func main() {
    cassy := cat{animal{3, "white", "meow"}, true}
    kitty := cat{animal{2, "black", "meow"}, true}
    missy := cat{animal{1, "brown", "meow"}, true}
    cats := []cat{cassy, kitty, missy}

    rocky := dog{animal{4, "brown", "woof"}, true}
    lucy := dog{animal{3, "white", "woof"}, true}
    tucker := dog{animal{2, "black", "woof"}, true}
    dogs := []dog{rocky, lucy, tucker}

    for i, val := range cats {
        fmt.Println(i, " - ", val)
    }

    for i, val := range dogs {
        fmt.Println(i, " - ", val)
    }
}

// 0  -  {{3 white meow} true}
// 1  -  {{2 black meow} true}
// 2  -  {{1 brown meow} true}
// 0  -  {{4 brown woof} true}
// 1  -  {{3 white woof} true}
// 2  -  {{2 black woof} true}

It is a simple code so I don't think I would need to explain here...Well alright.. So we have two types here with dog() and cat(), bunch of dogs and cats, and two for loops to loop through the dogs and cats and finally print out the dogs and cats.

See the problem here? Same as the previous post, why do we need to write two different functions (in this case it's the for loops) to do the same thing?

But what's different from the previous post is that we have different types here: int, string, and bool in the type.

Instead why don't we include our friend interface:

package main

import "fmt"
type animals interface{}
type animal struct {
    age   int
    color string
    sound string
}

type cat struct {
    animal
    bossy bool
}

type dog struct {
    animal
    friendly bool
}
func main() {
    cassy := cat{animal{3, "white", "meow"}, true}
    kitty := cat{animal{2, "black", "meow"}, true}
    missy := cat{animal{1, "brown", "meow"}, true}

    rocky := dog{animal{4, "brown", "woof"}, true}
    lucy := dog{animal{3, "white", "woof"}, true}
    tucker := dog{animal{2, "black", "woof"}, true}

    friends := []animals{cassy, kitty, missy, rocky, lucy, tucker}

    for i, val := range friends {
        fmt.Println(i, " - ", val)
    }
}


// 0  -  {{3 white meow} true}
// 1  -  {{2 black meow} true}
// 2  -  {{1 brown meow} true}
// 3  -  {{4 brown woof} true}
// 4  -  {{3 white woof} true}
// 5  -  {{2 black woof} true}

So here we have got an empty animal interface, recall the statement of 'This is useful when we want to store different types of data.', we definitely have a bunch of different types for the type cat and dog.

It is difficult to specify which type do we need exactly, so why don't we just chuck everything into something(empty interface) that accept everything?

Or you can do this too:

Empty Interface as param

package main

import (
    "fmt"
)

type animal struct {
    age   int
    color string
    sound string
}

type cat struct {
    animal
    bossy bool
}

type dog struct {
    animal
    friendly bool
}
func result(a interface{}) { // Here!
    fmt.Println(a)
}

func main() {
    cassy := cat{animal{3, "white", "meow"}, true}
    rocky := dog{animal{4, "brown", "woof"}, true}

    result(cassy)
    result(rocky)
}

// {{3 white meow} true}
// {{4 brown woof} true}

Here I only included a dog and a cat just to reduce the complexity.

Or this:

Empty Interface as slice

package main

import "fmt"

type animal struct {
    age   int
    color string
    sound string
}

type cat struct {
    animal
    bossy bool
}

type dog struct {
    animal
    friendly bool
}
func main() {
    cassy := cat{animal{3, "white", "meow"}, true}
    kitty := cat{animal{2, "black", "meow"}, true}
    missy := cat{animal{1, "brown", "meow"}, true}

    rocky := dog{animal{4, "brown", "woof"}, true}
    lucy := dog{animal{3, "white", "woof"}, true}
    tucker := dog{animal{2, "black", "woof"}, true}

        // Here!
    friends := []interface{}{cassy, missy, kitty, rocky, lucy, tucker}

    fmt.Println(friends)
}

// [{{3 white meow} true} {{1 brown meow} true} {{2 black meow} true} {{4 brown woof} true} {{3 white woof} true} {{2 black woof} true}]

Which will return a slice (array).

The basic idea of interface: to prevent the repetition when calling methods. Empty interface? To prevent the repetition when calling methods with different types.

Thank you for reading my post, I am still a newbie Gopher but working hard to become a qualified Gopher :3

Discussion

pic
Editor guide